Linux應用程式設計—12.信号
信号用于核心層與應用層之間、應用層與應用層之間傳遞控制指令。在終端下面通過鍵盤輸入“Ctrl + C”就是向作業系統發送了一個控制指令,告訴系統結束目前程序。
在終端下輸入“kill -l”即可檢視系統支援的是以控制指令。如下圖1所示。

圖1 檢視所有控制指令
如圖所示,一共有64個指令。經常使用的“Ctrl + C”就是9号:SIGINT指令,用來結束目前程序。如果父子程序同時運作,在中斷下輸入“Ctrl + C”隻能終止父程序,子程序還在運作。這種情況,我們可以通過控制指令“kill”來結束這個子程序。
檢視控制指令“kill”的說明。
NAME
kill - send a signal to a process
SYNOPSIS
kill [options] <pid> [...]
DESCRIPTION
The default signal for kill is TERM. Use -l or -L to list available
signals. Particularly useful signals include HUP, INT, KILL, STOP,
CONT, and 0. Alternate signals may be specified in three ways: -9,
-SIGKILL or -KILL. Negative PID values may be used to choose whole
process groups; see the PGID column in ps command output. A PID of -1
is special; it indicates all processes except the kill process itself
and init.
kill指令的作用是發送一個信号到程序。預設情況下這個kill信号是結束程序“TERM”。假如結束程序id号為:7436的程序。在在中斷下輸入:kill 7436即可。
12.1 signal()函數用來改變信号的處理
函數原型,sighandler_t signal(int signum, sighandler_t handler);其中handler是函數指針,typedef void (*sighandler_t)(int);當觸發了某一個信号,會去執行handler入口的函數。原本“SIGINT”的預設功能是結束目前程序,但是如果使用signal()函數重新處理後,當觸發到“SIGINT”後,轉去執行handler函數,覆寫了以前的功能。設計這樣一段程式,使用signal()函數重新改寫SIGINT,當鍵盤輸入“Ctrl + C”後,列印字元串“SIGINT triged.”,然後代碼每隔1秒鐘列印計數值一次。為了友善後續終止這個程序,列印目前程序id号,供終端關閉該程序。
代碼如下:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void function(int signl);
int main(void)
{
int i = 0;
signal(SIGINT, function);
printf("Process pid = %d\n.", getpid());
while(1)
{
printf("Count to %d.\n", ++i);
sleep(1);
}
return 0;
}
void function(int signl)
{
printf("SIGINT triged.\n");
}
運作結果:
圖2 運作結果
當使用者輸入“Ctrl + C”時,沒有結束目前程序,計數繼續,并且列印SIGINT triged.代碼運作符合預期。結束目前程序可以通過另一個終端輸入:kill 10773.結果如下圖3所示:
圖3 通過kill指令結束程序
改寫代碼,使之具有之前的功能——結束目前程序,隻需在被觸發調用的函數後面加上一個退出即可。exit(1)。修改後代碼如下:
void function(int signl)
{
printf("SIGINT triged.\n");
exit(1);
}
運作結果如下:
圖4 運作結果
12.2 kill()函數
kill()函數是向一個程序發送信号。函數原型如下:int kill(pid_t pid, int sig);入參分别是程序id号pid與信号。傳回值,成功:0;失敗:-1。
編寫一段代碼,通過main()函數入參傳入程序id号,并且代碼中通過調用kill()函數将這個程序終止。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int *argc, char *argv[])
{
kill(atoi(argv[1]), SIGKILL);
return 0;
}
通過gcc編譯為KILL 可執行檔案,
在終端啟動上一個代碼,代碼正常運作,并且列印程序id号:11099,在另一個終端中執行:./KILL 11099,11099的程序結束。運作結果如下圖5所示:
圖5 運作結果
12.3 總結
信号用于核心層與應用層、應用層與應用層之間傳遞控制指令。Linux下有64種信号類型。使用signal()函數可以改寫信号的作用,但有的信号不支援。kill()函數可以向一個程序發送某個信号。