信號通訊是在軟件層面上對中斷機制的一種模擬。信號是進程間通訊機制中惟一的異步通訊機制。異步
信號能夠直接進行用戶空間進程和內核進程之間的交互,內核進程也能夠利用它來通知用戶空間進程發生了哪些系統事件。它能夠在任什麼時候候發給某一進程,而無需知道該進程的狀態。若是該進程當前並未處於執行態,則該信號就由內核保存起來,直到該進程恢復執行再傳遞給它爲止。函數
信號事件的產生有硬件來源(如按下鍵盤或者其餘硬件故障)和軟件來源,軟件來源除了軟件調用,還包括一些非法運算等操做。指針
進程能夠經過3種方式來響應一個信號:rest
一、忽略信號:即對信號不作任何處理,其中,有兩個信號不能忽略,SIGKILL & SIGSTOP。code
二、捕捉信號:定義信號處理函數,當信號發生時,執行相應的操做。進程
三、執行默認操做:Linux對每種信號都規定了默認操做,下表包含了部分的定義:事件
信號的相關函數包括信號的發送和設置,具體以下:字符串
發送信號的函數:kill() raise() sigqueue()get
設置信號的函數:signal() sigaction() setitimer()原型
其餘函數:alarm() pause()
信號發送:kill() raise()
kill() 函數同kill 系統命令同樣,能夠發送信號給進程或是進程組(實際上,kill 系統命令就是調用 kill() 函數。須要注意的是,它不只能夠終止進程(發送 SIGTERM信號),也能夠向進程發送其餘信號。
注意:raise() 函數只能向進程自身發送信號
函數原型:
int kill(pid_t pid,int sig);
int raise(int sig);
說明:pid 爲進程號;sig 爲信號類型號
raise() 例程:進程在執行while(1)循環輸出字符串的時候調用raise(SIGSTOP)使進程中止 \
/* raise.c */ #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { printf("PID: %d\n",getpid()); while(1){ printf("run\n"); raise(SIGSTOP); } }
程序輸出:
PID: 55859 run [1]+ Stopped ./a.out
能夠看到,進程在輸出了第句run以後調用raise(SIGSTOP)使進程中止了,使用命令 "ps -ef | grep a.out" 能夠看到進程並無消失,確認進程只是暫停。使用 "kill -9 55859" 殺死進程。
kill() 例程:子進程間隔10us打印一串字符,父進程100us後 kill 子進程。
/* kill.c */ #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid; pid = fork(); if(pid == -1){ perror("fork failed:"); exit(-1); } if(pid == 0){ while(1){ printf("child\n"); sleep(1); } }else{ sleep(3); kill(pid,SIGINT); sleep(3); exit(0); } }
alarm() 能夠在進程中設置一個定時器,當定時器指定的時間到時,它就向進程發送SIGALARM信號。一個進程只能有一個鬧鐘,重複設置,前面的鬧鐘會被覆蓋。
示例:
#include <unistd.h> #include <stdio.h> #include <stdlib.h> int main() { alarm(3); while(1){ printf("run\n"); sleep(1); pause(); } printf("waken up\n"); }
程序輸出:
run Alarm clock
註釋掉 pause(); 的程序輸出:
run run run Alarm clock
信號的設置:signal() sigaction()
signal() 用於設置信號的處理函數。主要用於前32種非實時信號的處理,不支持信號傳遞信息。
注:signal() 是UNIX系統的遺留版本,不一樣的系統表現不一且在有的系統上會出現信號丟失的問題。且在man中亦提到,’應避免使用signal(),使用sigaction()代替‘。因此這裏咱們就不討論signal(),直接使用sigaction()。
函數原型:
int sigaction(int signum,const struct sigaction *act,struct sigacton *oldact);
說明:signum - 信號類型,除SIGKILL & SIGSTOP 外的任何一個信號;act - 指向sigaction結構體的指針,包含對特殊信號的處理;oldact - 保留信號原先的處理方式。
struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); };
說明:
sa_handler 和 sa_sigaction 二者只能定義一個,且sa_sigaction 是 sa_handler的升級版本,因爲sa_sigaction又太複雜,在這裏咱們就不討論sa_sigaction。
sa_handler 是一個函數指針,指向信號處理函數。它既能夠是用戶自定義的處理函數,也能夠爲SIG_DFL(採用默認的處理方式)或SIG_IGN(忽略信號)。信號處理函數只有一個參數,即信號類型。
sa_mask是一個信號集合,用來指定在信號處理函數執行過程當中哪些信號被屏蔽。
sa_flags 中包含了許多標誌位,都是和信號處理相關的選項。常見可選值包括(SA_NODEFER/SA_NOMASK/SA_NOCLDSTOP/SA_RESTART/SA_ONESHOT/SA_RESETHAND)
sigaction() 示例:
/* signal.c */ #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void my_func(int sign_no) { if(sign_no == SIGINT){ printf("I have got SIGINT\n"); }else if(sign_no == SIGQUIT){ printf("I have got SIGQUIT\n"); } } int main() { struct sigaction action; //初始化結構體 sigaction(SIGINT,0,&action); action.sa_handler = my_func; sigaction(SIGINT,&action,0); sigaction(SIGQUIT,0,&action); action.sa_handler = my_func; sigaction(SIGQUIT,&action,0); printf("Waiting for signal SIGINT & SIGQUIT\n:"); pause(); exit(0); }