信號捕捉(signal、sigaction)

信號的基本屬性:軟中斷,由內核發送,內核處理。某個進程通過內核向另一個進程發送信號時(引起信號產生的五個因素),另一個進程將會陷入內核進行中斷處理,未決信號集中相應信號置1,當遞達后,置0。如果阻塞信號集相應信號為1,則該信號處于未決狀態。處于未決狀態中的信號,多次發送時,只是執行一次,因為在未決信號集中只是記錄了該信號的狀態,沒有記錄發送的次數。信號抵達后,內核進行處理。處理方式有三:默認處理方式(5種);忽略(丟棄)和捕捉。下面說明捕捉機制。

signal和sigaction函數只是完成對一個信號進行注冊的功能,而對信號的捕捉的處理都是由內核完成的。當對一個信號進行注冊后,內核對其捕捉同時調用其注冊時對應的用戶處理函數。

1signal函數

typedef void (*sighandler_t)(int);? //定義一個函數類型 sighandler_t

sighandler_t signal(int signum, sighandler_t handler);

作用:注冊一個信號捕捉函數

返回值:成功返回sighandler_t類型的函數(或函數首地址);失敗則返回一個宏:SIG_ERR。注意判斷該函數的返回值: sighandler ret = signal(·······);if(ret==SIG_ERR)

第一個參數為信號;第二個參數為sighandler_t類型函數(即返回值為void,形參為int)。

注意:該函數由ANSI定義,由于歷史原因在不同版本的Unix和不同版本的Linux中可能有不同的行為。因此應該盡量避免使用它,取而代之使用sigaction函數。

#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>typedef void (*sighandler_t) (int);  //定義sighandler_t類型void catchsigint(int signo)
{printf("-----------------catch\n");
}int main(void)
{sighandler_t handler;handler = signal(SIGINT, catchsigint);  //注冊2號信號if (handler == SIG_ERR) {perror("signal error");exit(1);}                            //判斷返回值while (1);return 0;
}

[root@localhost 01_signal_test]# ./signal2

^C-----------------catch???????????????? //Ctrl+C?

^C-----------------catch??????????? ?????//Ctrl+C?

^\Quit (core dumped) ????????????????//Ctrl+\

只要一發送2號信號,就會執行相應函數。

2sigaction函數

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);?

作用:對某個信號進行注冊(同signal),即對某個信號之前對應的處理方式(函數)進行修改。

返回值:成功0;失敗-1,設置errno。

參數:

act傳入參數,新的處理方式。

oldact傳出參數,舊的處理方式。

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:該元素是過時的,不應該使用,POSIX.1標準將不指定該元素。(棄用)

sa_sigaction:當sa_flags被指定為SA_SIGINFO標志時,使用該信號處理程序。(很少使用)?

重點掌握:

sa_handler:指定信號捕捉后的處理函數名(即注冊函數)。也可賦值為SIG_IGN表忽略 SIG_DFL表執行默認動作;

sa_mask: 調用信號處理函數時,所要屏蔽的信號集合(信號屏蔽字)。注意:僅在處理函數被調用期間屏蔽生效,是臨時性設置;sa_mask也是一個字(64位),只是在執行相應的用戶處理函數期間生效。即在執行用戶處理函數期間, sa_mask屏蔽的信號也不能遞達,處于未決狀態。如果sa_mask未屏蔽,則響應信號,中斷嵌套。相當于此期間,sa_mask代替了mask。

sa_flags:通常設置為0,表示用默認屬性。默認屬性即為:sa_mask中將自己屏蔽,即該信號的注冊函數執行期間,再次向進程發送該信號,該信號不能遞達,處于未決狀態。

最后一個參數如果不關心之前的處理方式,可以為NULL

3)信號捕捉機制

進程正常運行時,默認PCB中有一個信號屏蔽字,假定為mask,它決定了進程自動屏蔽哪些信號。當注冊了某個信號捕捉函數,捕捉到該信號以后,要調用該函數。而該函數有可能執行很長時間,在這期間所屏蔽的信號不由mask來指定。而是用sa_mask來指定。調用完信號處理函數,再恢復為mask。

sa_flags為0時,XXX信號捕捉函數執行期間,XXX信號自動被屏蔽。

阻塞的常規信號(1-31)不支持排隊,產生多次只記錄一次。(后32個實時信號支持排隊)

內核實現信號捕捉的過程如下:

首先,處于用戶態(user mode)的某個進程在執行到某個指令時突然接收某個信號(軟中斷,終端按鍵產生;硬件異常產生;命令產生;系統調用產生或者軟件條件產生),會暫停執行下一條指令而陷入內核進入內核態。

內核在處理這一異常后,在準備會用戶態之前先處理可以遞達該進程的信號。

如果該信號的處理方式為捕捉,則內核對該信號進行捕捉,同時調用相應的用戶處理函數,回到用戶態執行相應的用戶處理函數(注意不是回到主控制流程)。

在用戶處理函數執行完返回時,再次執行系統調用sigretum再次進入內核。因為函數執行完需要返回到該函數的調用點,而該函數是內核調用的,因此需要再次返回到內核。

最后,從內核再次返回到用戶模式,從上次中斷處繼續執行下一條指令。

?

//練習1:為某個信號設置捕捉函數;驗證在信號處理函數執行期間,該信號多次遞送,那么只在處理函數之行結束后,處理一次;驗證sa_mask在捕捉函數執行期間的屏蔽作用。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>void docatch(int signo)  //用戶處理函數
{printf("the %dth signal is catched\n", signo);sleep(10); printf("-------finish------\n");
}
int main(void)
{int ret;struct sigaction act;act.sa_handler = docatch;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask, SIGQUIT);  //sa_mask屏蔽字中,3號信號置1act.sa_flags = 0;  //默認屬性   信號捕捉函數執行期間,自動屏蔽本信號ret = sigaction(SIGINT, &act, NULL);   //注冊2號信號if (ret == -1) {perror("sigaction error");exit(1);}while (1);return 0;
}

[root@localhost 01_signal_test]# ./test_sigac

^Cthe 2th signal is catched ??// 2號信號 Ctrl +C

-------finish------

^Cthe 2th signal is catched ?// 2號信號 Ctrl +C

^C^C^C^C^C^C^C^C^C^C^C^C^C-------finish------? ?// 執行期間,發多個2號信號

the 2th signal is catched

-------finish------???????? ???//但是只是執行了一次

^Cthe 2th signal is catched

^\^\^\^\^\^\^\^\^\^\^\^\-------finish------?? // 執行期間,發多個3號信號

Quit (core dumped)?? //2號信號處理完后,處理2號,則退出進程,結束。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385328.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385328.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385328.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

1090 Highest Price in Supply Chain (25)(25 分)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;經銷商&#xff09;, and suppliers&#xff08;供應商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

時序競態(競態條件)

產生原因&#xff1a;仍然以前文實現的sleep函數為例&#xff0c;如果進程在執行完alarm函數后&#xff0c;突然失去CPU&#xff0c;被阻塞等待&#xff08;這是有可能的&#xff0c;進程在執行過程中&#xff0c;若非原子操作&#xff0c;都有可能隨時失去CPU&#xff09;&…

1106 Lowest Price in Supply Chain (25)

A supply chain is a network of retailers&#xff08;零售商&#xff09;, distributors&#xff08;經銷商&#xff09;, and suppliers&#xff08;供應商&#xff09;-- everyone involved in moving a product from supplier to customer. Starting from one root suppli…

【Leetcode | 順序刷題 】二分查找目錄

二分查找序號題號129. 兩數相除 50. Pow(x, n) 69. x 的平方根

sigsuspend函數(mysleep函數的改進)

可以通過設置屏蔽SIGALRM的方法來控制程序執行邏輯&#xff0c;但無論如何設置&#xff0c;程序都有可能在“解除信號屏蔽”與“掛起等待信號”這個兩個操作間隙失去cpu資源。除非將這兩步驟合并成一個“原子操作”。sigsuspend函數具備這個功能。在對時序要求嚴格的場合下都應…

【Leetcode | 順序刷題】數學目錄

序號題號1 7. 整數反轉 28. 字符串轉換整數 (atoi)39. 回文數443. 字符串相乘

全局變量的異步I/O問題

全局變量的異步I/O問題同樣屬于時序競態問題&#xff0c;其本質就是多個進程或者同一個進程中的多個時序&#xff08;如主控程序和信號捕捉時的用戶處理函數&#xff09;對同一個變量進行修改時&#xff0c;它們的執行順序不一樣就會導致該變量最終的值不一樣&#xff0c;從而產…

【Leetcode | 03】String

字符串目錄序號題號33. 無重復字符的最長子串 151. 翻轉字符串里的單詞

可/不可重入函數

一個函數在被調用執行期間&#xff08;尚未調用結束&#xff09;&#xff0c;由于某種時序&#xff08;遞歸或者處理信號捕捉時等情況&#xff09;又被重復調用&#xff0c;稱之為“重入”。根據函數實現的方法可分為“可重入函數”和“不可重入函數”兩種。看如下程序。 可以看…

【Leetcode | 順序刷題】雜項目錄

序號題號類別1136. 只出現一次的數字位運算2137. 只出現一次的數字 II位運算3 260. 只出現一次的數字 III 位運算4191. 位1的個數位運算5231. 2的冪位運算6342. 4的冪位運算7 338. 比特位計數 位運算8405. 數字轉換為十六進制數位運算9371. 兩整數之和位運算10401. 二進制手表位…

SIGCHLD信號

&#xff08;1&#xff09;SIGCHLD信號產生的條件 1.子進程終止時會向父進程發送SIGCHLD信號&#xff0c;告知父進程回收自己&#xff0c;但該信號的默認處理動作為忽略&#xff0c;因此父進程仍然不會去回收子進程&#xff0c;需要捕捉處理實現子進程的回收&#xff1b; 2.子…

信號傳參

&#xff08;1&#xff09;發送信號傳參 前面已經知道從一個進程向另一個進程發送信號可以使用kill函數&#xff0c;但是kill函數在向進程發送信號的時候不能攜帶除了信號以外的其他信息&#xff0c;這時可以使用與kill相對應的sigqueue函數&#xff0c;該函數也是向一個進程發…

【Leetcode | 52】257. 二叉樹的所有路徑

給定一個二叉樹&#xff0c;返回所有從根節點到葉子節點的路徑。 說明: 葉子節點是指沒有子節點的節點。 示例: 輸入: 1 / \ 2 3 \ 5 輸出: ["1->2->5", "1->3"] 解釋: 所有根節點到葉子節點的路徑為: 1->2->5, 1->3 解法一&a…

623. 在二叉樹中增加一行

給定一個二叉樹&#xff0c;根節點為第1層&#xff0c;深度為 1。在其第 d 層追加一行值為 v 的節點。 添加規則&#xff1a;給定一個深度值 d &#xff08;正整數&#xff09;&#xff0c;針對深度為 d-1 層的每一非空節點 N&#xff0c;為 N 創建兩個值為 v 的左子樹和右子樹…

終端的概念

操作系統接口&#xff1a;用戶接口和程序接口。用戶接口分為聯機用戶接口和脫機用戶接口。脫機用戶接口出現在早期的批處理系統中&#xff08;將作業提前交給操作系統&#xff0c;作業完成的過程中用戶無法交互&#xff09;&#xff1b;聯機用戶接口即為終端&#xff08;所有輸…

終端的啟動流程

在Linux操作系統啟動時&#xff0c;首先加載的進程就是init進程&#xff08;ID為1&#xff09;&#xff0c;其余進程都是init進程產生的&#xff08;fork&#xff0c;然后exec金蟬脫殼&#xff09;&#xff0c;因此系統中所有進程都可以看成是init進程的子孫進程。可以通過ps a…

進程組(作業)

&#xff08;1&#xff09;概念和特性 進程組&#xff0c;也稱之為作業。BSD于1980年前后向Unix中增加的一個新特性。代表一個或多個進程的集合。每個進程都屬于一個進程組。在waitpid函數和kill函數的參數中都曾使用到。操作系統設計的進程組的概念&#xff0c;是為了簡化對多…

437. 路徑總和 III

給定一個二叉樹&#xff0c;它的每個結點都存放著一個整數值。 找出路徑和等于給定數值的路徑總數。 路徑不需要從根節點開始&#xff0c;也不需要在葉子節點結束&#xff0c;但是路徑方向必須是向下的&#xff08;只能從父節點到子節點&#xff09;。 二叉樹不超過1000個節…

會話(session)

一組進程形成一個進程組&#xff0c;一組進程組形成一個會話&#xff0c;即一個會話中可以包括多個進程組。 &#xff08;1&#xff09;創建會話 創建一個會話需要注意以下6點注意事項&#xff1a;1.調用進程不能是進程組組長&#xff08;不能是父進程&#xff09;&#xff0…

508. 出現次數最多的子樹元素和

給出二叉樹的根&#xff0c;找出出現次數最多的子樹元素和。一個結點的子樹元素和定義為以該結點為根的二叉樹上所有結點的元素之和&#xff08;包括結點本身&#xff09;。然后求出出現次數最多的子樹元素和。如果有多個元素出現的次數相同&#xff0c;返回所有出現次數最多的…