Linux系統程式設計—訊號捕捉
前面我們學習了訊號產生的幾種方式,而對於訊號的處理有如下幾種方式:
- 預設處理方式;
- 忽略;
- 捕捉。
訊號的捕捉,說白了就是抓到一個訊號後,執行我們指定的函式,或者執行我們指定的動作。下面詳細介紹兩個訊號捕捉操作引數:signal和sigaction。
##signal函式
函式原型:
sighandler_t signal(int signum, sighandler_t handler);
其中,sighandler定義是這樣的:typedef void (*sighandler_t)(int);
函式作用:
註冊一個訊號捕捉函式,也就是說,收到了某個訊號,就執行它所註冊的回撥函式。
函式引數:
signum:訊號編號,儘量用宏來寫,而別用數字,這樣更適合跨平臺;
handler:註冊的回撥函式;
函式缺陷:
由於歷史原因,該函式在不同版本的Unix和Linux系統中可能起到的效果不一樣,所以跨平臺性不佳,儘量避免使用它,取而代之使用通用性更好的sigaction函式。
#include
#include
void func()
{
printf("SIGQUIT catched!n");
}
int main()
{
signal(SIGQUIT, func);
while(1);
}
##sigaction函式
函式原型:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
函式作用:
與signal函式類似,用來註冊一個訊號捕捉函式;
返回值:
成功:0;失敗:-1,並設定errno;
引數:
signum:訊號編號,儘量用宏來寫,而別用數字,這樣更適合跨平臺;
act:傳入引數,新的訊號捕捉方式;
oldact:傳出引數,舊的訊號捕捉方式
這裡特別要注意引數中struct sigaction結構體,這也是這個函式的難點所在,下面詳細說明:
struct sigaction結構體
原型:
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_restorer和sa_sigaction這兩個成員一個已經被棄用了,另一個很少使用,所以我們暫且不管它們,重點掌握剩下的三個。
① sa_handler:指定訊號捕捉後的處理函式,即註冊回撥函式。該成員也可以賦值為SIG_IGN,表示忽略該訊號,也可註冊為SIG_DFL,表示執行訊號的預設動作。
② sa_mask:臨時阻塞訊號集(或訊號遮蔽字)先來看這樣一個情景:
某個訊號已經註冊了回撥函式,當核心傳遞這個訊號過來時,會先經過一個阻塞訊號集,先阻塞掉部分訊號。再去執行對應的回撥函式。如下圖示:
假如說,這個回撥函式回撥執行的時間比較長,比如2秒,在這2秒裡,又有其它的訊號過來,那程式是暫停當前回撥函式,去響應新的訊號,還是不管新來的訊號,先把當前回撥函式處理完再說?
正確的做法是,在執行回撥函式期間,使用sa_mask臨時的去替代程式的阻塞訊號集,保證回撥函式安心的執行完畢,再解除替代。注意:這個過程僅僅發生在回撥函式執行期間,是臨時性的設定。
③ sa_flags:通常設定為0,表示使用預設屬性。
再來看另外一個場景:
比如程式對SIGQUIT註冊了回撥函式,當回撥函式在執行期間,又來了SIGQUIT函式,這時,程式是響應還是不響應該訊號?這就是sa_flags的一個作用,當其設定為0時,表示使用預設屬性,也就是先不響應該訊號,而是執行完回撥函式再處理此訊號。
另外,阻塞的常規訊號不支援排隊,也就是說,執行回撥函式期間,再來千百個同個訊號時,系統只記錄一次。而後面的32個實時訊號則支援排隊。
#include
#include
#include
void func(int signal)
{
printf("SIGQUIT catched!n");
sleep(2); //用來模擬回撥函式執行很長時間
printf("func finished!n");
}
int main()
{
struct sigaction act;
act.sa_handler = func;
sigemptyset(&act.sa_mask); //先清空臨時阻塞訊號集
sigaddset(&act.sa_mask, SIGINT); // 執行回撥函式期間,遮蔽SIGINT
act.sa_flags = 0;
sigaction(SIGQUIT, &act, NULL); //註冊回撥函式
while(1);
return 0;
}
最後,最近很多小夥伴找我要Linux學習路線圖,於是我根據自己的經驗,利用業餘時間熬夜肝了一個月,整理了一份電子書。無論你是面試還是自我提升,相信都會對你有幫助!目錄如下:
免費送給大家,只求大家金指給我點個贊!
也希望有小夥伴能加入我,把這份電子書做得更完美!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2524/viewspace-2826412/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Linux系統程式設計:訊號捕捉Linux程式設計
- Python捕捉系統訊號Python
- 【Linux系統程式設計】Linux訊號列表Linux程式設計
- linux系統程式設計之訊號(一):中斷與訊號Linux程式設計
- Linux系統程式設計(22)——響應訊號Linux程式設計
- 【linux】系統程式設計-1-程式、管道和訊號Linux程式設計
- Linux系統程式設計(20)——訊號基本概念Linux程式設計
- Linux系統程式設計(21)——訊號的產生Linux程式設計
- Linux系統程式設計(24)——訊號的生命週期Linux程式設計
- linux系統程式設計之訊號(五):訊號集操作函式,訊號阻塞與未決Linux程式設計函式
- Linux系統程式設計之訊號中斷處理(下)Linux程式設計
- Linux系統程式設計之訊號中斷處理(上)Linux程式設計
- Linux訊號捕捉之sigactionLinux
- linux系統程式設計之訊號(三):訊號安裝、signal、kill,arise講解Linux程式設計
- linux系統程式設計之訊號(七):被訊號中斷的系統呼叫和庫函式處理方式Linux程式設計函式
- linux系統程式設計之訊號(四):alarm和可重入函式Linux程式設計函式
- linux系統程式設計之訊號(二):訊號處理流程(產生、註冊、登出、執行)Linux程式設計
- 【Linux網路程式設計-1】訊號Linux程式設計
- shell訊號捕捉命令 trap
- Linux系統程式設計之程式間通訊方式:訊息佇列Linux程式設計佇列
- 【linux】系統程式設計-6-POSIX標準下的訊號量與互斥鎖Linux程式設計
- 【linux】系統程式設計-2-訊息佇列Linux程式設計佇列
- 系統程式設計-訊號-總體概述和signal基本使用程式設計
- 系統程式設計——管道通訊程式設計
- Linux系統程式設計之程式間通訊方式:管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:管道(一)Linux程式設計
- Linux系統程式設計(11)——程式間通訊之有名管道Linux程式設計
- Linux系統程式設計之程式間通訊方式:命名管道(二)Linux程式設計
- Linux系統程式設計之程式間通訊方式:命名管道(一)Linux程式設計
- Linux系統程式設計【4】——檔案系統Linux程式設計
- Linux系統程式設計—有名管道Linux程式設計
- Linux系統程式設計入門Linux程式設計
- Linux系統程式設計基礎Linux程式設計
- 系統程式設計——IPC訊息佇列程式設計佇列
- 【Linux】Linux系統程式設計入門Linux程式設計
- 使用命令trap來捕捉訊號(轉)
- 在shell中捕捉訊號的命令(轉)
- Linux系統程式設計之程式介紹Linux程式設計