信號(signal)是在特定事件發生時由操作系統向進程發送的消息。它一種軟件中斷,是進程間唯一的異步通信方式。
信號有很多,常見的有:
- SIGINT:在鍵盤按下<Ctrl+C>組合鍵後產生,默認動作爲終止進程
- SIGQUIT:在鍵盤按下<Ctrl+\>組合鍵後產生,默認動作爲終止進程
- SIGKILL:無條件終止進程。本信號不能被忽略、處理和阻塞。默認動作爲終止進程。它向系統管理員提供了一種可以殺死任何進程的方法
- SIGALRM:定時器超時,超時的時間由系統調用alarm設置。默認動作爲終止進程
- SIGCHLD:子進程結束時,父進程會收到這個信號。默認動作爲忽略該信號
信號的捕捉和處理
信號的捕捉和處理由以下2個函數來完成,其中第一個函數也是由第二個函數實現的:
#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
參數signum指定信號的種類,比如SIGINT、SIGKILL等。
參數handler是一個函數指針,指定捕捉到該信號後的處理函數。
signal函數執行成功時返回信號處理函數指針,發生錯誤時返回SIG_ERR。
sigaction函數類似於signal函數,而且它完全可以替代後者,也更穩定。之所以穩定,是signal函數在UNIX系列的不同操作系統中可能存在區別,但sigaction函數完全相同。實際上現在很少用signal函數來編寫程序,它只是爲了保持對舊程序的兼容。
1. signal()函數
#include <stdio.h>
#include <signal.h>
/*信號處理函數*/
void handler_sigint(int signo)
{
printf("recv SIGINT\n");
}
int main()
{
/*安裝信號處理函數*/
signal(SIGINT, handler_sigint);
while(1)
;
return 0;
}
程序使用signal()安裝SIGINT的處理函數handler_sigint,然後進入無限循環。當接收到SIGINT信號時,程序自動跳轉到信號處理函數處執行,打印出提示信息。然後返回主函數繼續無限循環。執行結果如下:
2. sigaction()函數
sigaction函數中用到了一個結構體sigaction作爲參數。此結構體中的字段常用的有2個,sa_handler用來指定信號發生後的處理函數,sa_flags用來進行一些設定。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int temp = 0;
/*信號處理函數*/
void handler_sigint(int signo)
{
printf("recv SIGINT\n");
sleep(5);
temp += 1;
printf("the value of temp is: %d\n", temp);
printf("in handler_sigint, after sleep\n");
}
int main()
{
struct sigaction act;
/*賦值act結構*/
act.sa_handler = handler_sigint;
act.sa_flags = SA_NOMASK; //此設置意味着,對於可靠信號,發生了多少次,就調用信號處理函數多少次,即信號不會丟失
/*安裝信號處理函數*/
sigaction(SIGINT, &act, NULL);
while(1)
;
return 0;
}
運行上述程序後,在鍵盤上快速按下5次<Ctrl+C>組合鍵,屏幕上會連續打印出5行提示消息。在休眠5秒後,再將臨時變量temp的值依次打印出來。這是由於設定了sa_flags的值爲SA_NOMASK,因此程序能夠反覆響應信號SIGINT,程序從sleep()處嵌套調用信號處理函數handler_sigint,多次打印出“recv SIGINT”。睡眠5秒後,將temp的值打印出來並返回到本次信號處理程序的跳入點sleep()處,最後返回到主函數。