您好,登錄后才能下訂單哦!
這篇文章主要介紹了Linux如何實(shí)現(xiàn)信號捕捉,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
##signal函數(shù)
函數(shù)原型:
sighandler_t signal(int signum, sighandler_t handler);
其中,sighandler定義是這樣的:typedef void (*sighandler_t)(int);
函數(shù)作用:注冊一個信號捕捉函數(shù),也就是說,收到了某個信號,就執(zhí)行它所注冊的回調(diào)函數(shù)。
函數(shù)參數(shù):
signum:信號編號,盡量用宏來寫,而別用數(shù)字,這樣更適合跨平臺;
handler:注冊的回調(diào)函數(shù);
函數(shù)缺陷:
由于歷史原因,該函數(shù)在不同版本的Unix和Linux系統(tǒng)中可能起到的效果不一樣,所以跨平臺性不佳,盡量避免使用它,取而代之使用通用性更好的sigaction函數(shù)。
#include <stdio.h> #include <signal.h> void func() { printf("SIGQUIT catched!\n"); } int main() { signal(SIGQUIT, func); while(1); }
##sigaction函數(shù)
函數(shù)原型:
int sigaction(int signum, const struct sigaction act, struct sigaction oldact);
函數(shù)作用:與signal函數(shù)類似,用來注冊一個信號捕捉函數(shù);
返回值:
成功:0;失敗:-1,并設(shè)置errno;
參數(shù):
signum:信號編號,盡量用宏來寫,而別用數(shù)字,這樣更適合跨平臺;
act:傳入?yún)?shù),新的信號捕捉方式;
oldact:傳出參數(shù),舊的信號捕捉方式
這里特別要注意參數(shù)中struct sigaction結(jié)構(gòu)體,這也是這個函數(shù)的難點(diǎn)所在,下面詳細(xì)說明:
struct sigaction結(jié)構(gòu)體
原型:
struct sigaction { void (*sa_handler)(int); void (sa_sigaction)(int, siginfo_t , void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); };
這個結(jié)構(gòu)體成員很多,又很多是回調(diào)函數(shù)的形式,令人望而生畏。但實(shí)際上,需要掌握的只有三個。
首先,sa_restorer和sa_sigaction這兩個成員一個已經(jīng)被棄用了,另一個很少使用,所以我們暫且不管它們,重點(diǎn)掌握剩下的三個。
(1) sa_handler:指定信號捕捉后的處理函數(shù),即注冊回調(diào)函數(shù)。該成員也可以賦值為SIG_IGN,表示忽略該信號,也可注冊為SIG_DFL,表示執(zhí)行信號的默認(rèn)動作。
(2) sa_mask:臨時阻塞信號集(或信號屏蔽字)先來看這樣一個情景:
某個信號已經(jīng)注冊了回調(diào)函數(shù),當(dāng)內(nèi)核傳遞這個信號過來時,會先經(jīng)過一個阻塞信號集,先阻塞掉部分信號。再去執(zhí)行對應(yīng)的回調(diào)函數(shù)。如下圖示:
假如說,這個回調(diào)函數(shù)回調(diào)執(zhí)行的時間比較長,比如2秒,在這2秒里,又有其它的信號過來,那進(jìn)程是暫停當(dāng)前回調(diào)函數(shù),去響應(yīng)新的信號,還是不管新來的信號,先把當(dāng)前回調(diào)函數(shù)處理完再說?
正確的做法是,在執(zhí)行回調(diào)函數(shù)期間,使用sa_mask臨時的去替代進(jìn)程的阻塞信號集,保證回調(diào)函數(shù)安心的執(zhí)行完畢,再解除替代。注意:這個過程僅僅發(fā)生在回調(diào)函數(shù)執(zhí)行期間,是臨時性的設(shè)置。
(3) sa_flags:通常設(shè)置為0,表示使用默認(rèn)屬性。
再來看另外一個場景:
比如進(jìn)程對SIGQUIT注冊了回調(diào)函數(shù),當(dāng)回調(diào)函數(shù)在執(zhí)行期間,又來了SIGQUIT函數(shù),這時,進(jìn)程是響應(yīng)還是不響應(yīng)該信號?這就是sa_flags的一個作用,當(dāng)其設(shè)置為0時,表示使用默認(rèn)屬性,也就是先不響應(yīng)該信號,而是執(zhí)行完回調(diào)函數(shù)再處理此信號。
另外,阻塞的常規(guī)信號不支持排隊(duì),也就是說,執(zhí)行回調(diào)函數(shù)期間,再來千百個同個信號時,系統(tǒng)只記錄一次。而后面的32個實(shí)時信號則支持排隊(duì)。
#include <stdio.h> #include <signal.h> #include <unistd.h> void func(int signal) { printf("SIGQUIT catched!\n"); sleep(2); //用來模擬回調(diào)函數(shù)執(zhí)行很長時間 printf("func finished!\n"); } int main() { struct sigaction act; act.sa_handler = func; sigemptyset(&act.sa_mask); //先清空臨時阻塞信號集 sigaddset(&act.sa_mask, SIGINT); // 執(zhí)行回調(diào)函數(shù)期間,屏蔽SIGINT act.sa_flags = 0; sigaction(SIGQUIT, &act, NULL); //注冊回調(diào)函數(shù) while(1); return 0; }
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Linux如何實(shí)現(xiàn)信號捕捉”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。