信號是軟件層面上的異常
(一)Linux信號
可以通過man 7 signal 查看Linux提供的標準信號。其中描述的信號的編號在不同的處理器體系結構的差異有所不同。
(二)信號傳送的步驟
傳送一個信號到目的進程通常由兩個不同的步驟組成:
(1)發送信號
發送信號的原因:
a)內核檢測到一個系統事件
b)一個進程調用了kill函數,顯式地要求內核發送一個信號給目的進程。
內核通過更新目的進程的上下文的某個狀態,發送一個信號給目的進程
發送信號的方式:
a)通過/bin/kill程序發送信號
b)通過鍵盤發送
常用的與鍵盤相關的信號:
SIGINT :來自鍵盤的終端信號(CTRL+C)
SIGQUIT:來自鍵盤的退出信號(CTRL +\)
c)通過kill函數發送
函數原型如下:
#include<sys/type.h>
#include<signal.h>
int kill(pid_t pid , int sig);
如果pid大於0,則給進程pid 發送信號sig,如果pid小於0,則給abs(pid)進程組中的每個進程發送信號sig。如果pid等於0,則不發送信號
d)通過alarm函數發送
alarm - set an alarm clock for delivery of a signal
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds.
(2)接收信號
當目的進程被內核強迫以某種方式對信號的發送做出反應時,目的進程就接收了信號。
內核爲每個進程在pending位向量中維護着待處理信號的集合,在blocked位向量中維護着被阻塞的信號集合,傳送一個類型爲k的信號,內核就會設置pending中的k位,接受一個類型爲k的信號,內核就會清除pending中的k位。
每個信號類型都有一個預定義的默認行爲,是如下當中的一種:
a)進程終止
b)進程終止並轉儲存儲器
c)進程停止直到被SIGCONT信號重啓
d)進程忽略該信號
進程可以通過signal函數修改和信號相關聯的默認行爲,SIGSTOP和SIGKILL兩個信號的默認行爲是不能修改的。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum的值爲:SIG_IGN,則忽略類型爲signum的信號
signum的值爲:SIG_DFL,則類型爲signum的信號行爲恢復爲默認行爲
signum的值爲:其他值,則設置類型爲signum的信號的行爲是用戶定義的函數(信號處理程序)。只要進程接收到一個類型爲signum信號,就調用這個程序
信號處理問題分析的三大要點
(1)待處理信號被阻塞
假設一個進程捕獲了一個類型爲k的信號,且當前正在運行它的信號處理程序,則如果另外一個類型爲k的信號傳遞給這個進程,則這個類型爲k的信號將變成待處理的,不會被接收,直到處理程序返回。
(2)待處理信號不會排隊
任意類型的信號,最多只能有一個待處理的信號,所以當上面描述的已經有一個類型爲k的待處理信號的時候,後續的傳遞到這個進程的待處理信號都將被直接丟棄。
(3)系統調用可以被中斷
在某些系統中當處理程序捕捉到一個信號時,被中斷的慢速系統調用在信號處理程序返回時將不再繼續,而是立即返回一個錯誤條件,並設置errno爲EINTR。