前面我們學習了信號產生的幾種方式,而對于信號的處理有如下幾種方式:
默認處理方式;
忽略;
捕捉。
信號的捕捉,說白了就是抓到一個信號后,執行我們指定的函數,或者執行我們指定的動作。下面詳細介紹兩個信號捕捉操作參數:signal和sigaction。
##signal函數
函數原型:
sighandler_t signal(int signum, sighandler_t handler);
其中,sighandler定義是這樣的:typedef void (*sighandler_t)(int);
函數作用:注冊一個信號捕捉函數,也就是說,收到了某個信號,就執行它所注冊的回調函數。
函數參數:
signum:信號編號,盡量用宏來寫,而別用數字,這樣更適合跨平臺;
handler:注冊的回調函數;
函數缺陷:
由于歷史原因,該函數在不同版本的Unix和Linux系統中可能起到的效果不一樣,所以跨平臺性不佳,盡量避免使用它,取而代之使用通用性更好的sigaction函數。
##sigaction函數
函數原型:
int sigaction(int signum, const struct sigaction act, struct sigaction oldact);
函數作用:與signal函數類似,用來注冊一個信號捕捉函數;
返回值:
成功:0;失敗:-1,并設置errno;
參數:
signum:信號編號,盡量用宏來寫,而別用數字,這樣更適合跨平臺;
act:傳入參數,新的信號捕捉方式;
oldact:傳出參數,舊的信號捕捉方式
這里特別要注意參數中struct sigaction結構體,這也是這個函數的難點所在,下面詳細說明:
struct sigaction結構體
原型:
這個結構體成員很多,又很多是回調函數的形式,令人望而生畏。但實際上,需要掌握的只有三個。
首先,sa_restorer和sa_sigaction這兩個成員一個已經被棄用了,另一個很少使用,所以我們暫且不管它們,重點掌握剩下的三個。
(1) sa_handler:指定信號捕捉后的處理函數,即注冊回調函數。該成員也可以賦值為SIG_IGN,表示忽略該信號,也可注冊為SIG_DFL,表示執行信號的默認動作。
(2) sa_mask:臨時阻塞信號集(或信號屏蔽字)先來看這樣一個情景:
某個信號已經注冊了回調函數,當內核傳遞這個信號過來時,會先經過一個阻塞信號集,先阻塞掉部分信號。再去執行對應的回調函數。如下圖示:
假如說,這個回調函數回調執行的時間比較長,比如2秒,在這2秒里,又有其它的信號過來,那進程是暫停當前回調函數,去響應新的信號,還是不管新來的信號,先把當前回調函數處理完再說?
正確的做法是,在執行回調函數期間,使用sa_mask臨時的去替代進程的阻塞信號集,保證回調函數安心的執行完畢,再解除替代。注意:這個過程僅僅發生在回調函數執行期間,是臨時性的設置。
(3) sa_flags:通常設置為0,表示使用默認屬性。
再來看另外一個場景:
比如進程對SIGQUIT注冊了回調函數,當回調函數在執行期間,又來了SIGQUIT函數,這時,進程是響應還是不響應該信號?這就是sa_flags的一個作用,當其設置為0時,表示使用默認屬性,也就是先不響應該信號,而是執行完回調函數再處理此信號。
另外,阻塞的常規信號不支持排隊,也就是說,執行回調函數期間,再來千百個同個信號時,系統只記錄一次。而后面的32個實時信號則支持排隊。
責編AJX
-
Linux
+關注
關注
87文章
11339瀏覽量
210118 -
操作系統
+關注
關注
37文章
6882瀏覽量
123582 -
信號
+關注
關注
11文章
2804瀏覽量
77003
發布評論請先 登錄
相關推薦
評論