學習Unix——發送信號

一、發送信號的方式

發送信號的方式有幾種:

1、由鍵盤觸發的信號(只能發送一些比較特殊的信號)

SIGINT (2):ctrl+c 中斷符

SIGQUIT (3):ctrl+\\ 退出符

SIGTSTP (20):ctrl+z 停止符

2、由錯誤和異常引發的信號

SIGILL (4) 進程試圖執行非法指令

SIGBUS (7) 硬件或對齊錯誤

SIGFPE (8) 算術異常

SIGSEGV (11) 無法內存訪問

SIGPIPE (13) 向無讀取進程的管道寫入

SIGSTKFLT (16) 協處理器棧錯誤

SIGXFSZ (25) 文件資源超限

SIGPWR (30) 斷電

SIGSYS (31) 進程試圖執行無效系統調用

3、用專門的系統命令發送信號

kill [-信號] PIDs

若不指明具體的信號,缺省發送 SIGTERM (15) 信號。

該信號允許用戶優雅地終止進程。進程可以選擇捕獲該信號,並在臨終之前完成必要的清理和善後工作。但如果捕獲了該信號,卻死賴著不走,則有流氓進程之嫌。

若要指明具體信號,可以使用信號編號,也可以使用信號名稱,而且信號名稱中的“SIG”前綴可以省略不寫。例如:

kill -9 1234

kill -SIGKILL 1234

kill -KILL 1234

kill -9 -1 (終止所有進程)

接收信號的進程可以是一個、多個或所有的(PIDs 取 -1)。拆機用戶可以發送任何進程,而普通用戶只能發送自己的進程。

二、發送信號的系統函數

1、函數 kill

#include

#include <signal.h>

int kill(pid_t pid, int sig);

返回值:成功(至少發出去一個信號)返回 0,失敗返回 -1

(1)函數功能

向指定進程或進程組發送信號

(2)參數解析

kill 的 pid 參數有以下 4 種不同的情況。

pid > 0 將該信號發送給進程 ID 為 pid 的進程

pid == 0 將該信號發送給與發送進程屬於同一進程組的所有進程(這些進程的進程組 ID 等於發送進程的進程組 ID),而且發送進程具有權限向這些進程發送信號。這裡用的術語“所有進程”不包括實現定義的系統進程集。對於大多數 UNIX 系統,系統進程集包括內核進程和 init (pid 為 1)。

pid < 0 將信號發送給其進程組 ID 等於 pid 絕對值,而且發送進程具有權限向其發送信號的所有進程。如前所述,所有進程並不包括系統進程集中的進程。

pid == -1 將該信號發送給發送進程有權限向它們發送信號的所有進程。若茜所述,所有進程不包括系統進程集中的進程。

參數 sig 為信號編號取 0 可用於檢查 pid 進程是否存在,如果不存在 kill 函數返回 -1,且 errno 為 ESRCH。

(3)示例說明

//示例一

//使用kill函數發送信號

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

#include

void fa(int signo)

{

printf("捕獲到了信號%d\\n",signo);

}

int main(void)

{

//使用fork函數創建子進程

pid_t pid = fork();

if(-1 == pid)

{

perror("fork"),exit(1);

}

if(0 == pid) //子進程

{

printf("pid = %d\\n",getpid());

//設置對信號50進行自定義處理

signal(50,fa);

while(1);

}

sleep(1);

//判斷子進程是否存在

if(0 == kill(pid,0))

{

printf("父進程發送信號50\\n");

kill(pid,50);

}

return 0;

}

輸出結果:

pid = 4569

父進程發送信號50

捕獲到了信號50

學習Unix——發送信號

//示例二 殺死進程

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <signal.h>

#include

int main(void)

{

pid_t pid;

if((pid=fork())<0)

{

perror("fork");

}

else if(pid==0)

{

printf("這是子進程,pid=%d,",getpid());

printf("父進程的pid=%d\\n",getppid());

printf("按回車鍵,終止父進程\\n");

getchar();

kill(getppid(), SIGTERM);

}

else

{

printf("這是父進程,pid=%d\\n",getpid());

while (1)

pause();

}

return 0;

}

輸出結果:

這是父進程,pid=4705

這是子進程,pid=4706,父進程的pid=4705

按回車鍵,終止父進程

已終止

(4)示例解析

示例一,發送信號 50 給子進程。如果 kill 第二個參數 sig 取 0,可判斷子進程是否存在。

示例二,發送 SIGTERM 給指定父進程。殺死特定進程。

2、函數 raise

#include <signal.h>

int raise(int sig);

返回值:成功返回 0,失敗返回非 0

(1)函數功能

向調用進程自己發送信號

(2)參數解析

sig 為信號編號

(3)函數解析

raise 函數實際上是給調用進程或者線程發送信號。

對於單線程應用來說,它相當於 kill (getpid (), sig);

對於多線程應用來說,它相當於 pthread_kill (pthread_self (), sig);

若所發信號被捕獲,raise 函數會在信號處理函數返回後返回。

(4)示例說明

//示例一

//使用raise函數發送信號

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

void fa(int signo)

{

printf("捕獲到了信號%d\\n",signo);

}

int main(void)

{

//設置信號2進行自定義處理

signal(2,fa);

int res = sleep(10);

if(0 == res)

{

printf("總算美美地睡了個好覺\\n");

}

else

{

printf("睡眠被打斷,還有%d秒沒有來得及睡\\n",res);

}

//使用raise函數發送信號2

raise(2);

while(1);

return 0;

}

輸出結果:

總算美美地睡了個好覺

捕獲到了信號2

學習Unix——發送信號

//示例二 進程自殺

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <signal.h>

int main (void)

{

printf ("按回車鍵,終止進程\\n");

getchar ();

raise (SIGTERM);

while (1)

pause ();

return 0;

}

輸出結果:

按回車鍵,終止進程

已終止

(5)示例解析

示例一,如果不使用 ctrl+c,而是等待 10 秒,raise 函數會發送信號 2。

示例二,raise 發送信號 SIGTERM,終止進程。

學習Unix——發送信號

學習編程(C語言/C++)並不難各位可以加下群466572167(資料和視頻),一起交流提升,編程不要覺得很難,雖說也有難度,但是學好了對以後的幫助是非常大。


分享到:


相關文章: