一. 信號的捕捉定義
????用戶提供一個處理函數, 要求內核在處理信號時必須切換到用戶態,執行這個函數, 這種方式就叫做信號的捕捉
二. 圖解信號的捕捉過程
????1. 由上圖可以看出,當處理信號的執行動作時用戶自定義的時候,此時就需返回該函數去調用該函數, 這就叫做信號的捕捉. 以前我們總是說進程收到信號時會在合適的時候取處理該信號, 現在可以看出,這個合適的時候就是當進程處理完中斷時, 需需要從內核態返回到用戶態的時候就需要處理能夠遞達的信號.舉個例子, 用戶注冊了一個信號, 當系統進程正在執行主控制流的時候, 發現有異常中斷產生, 此時系統從用戶態轉到內核態, 處理完異常中斷時, 需要返回到main函數時,檢測是否有可以遞達的信號,發現有一個可以遞達的信號, 而該信號的處理動作是用戶自定義類型(signalhandle), 于是系統就從內核態切換到用戶態去執行該信號的執行動作(signalhandle), 當處理完這個函數的時候, 系統不能直接返回到主控制流, 而是先通過 sigreturn 切換到內核狀態, 此時再繼續檢測是否有可以遞達的信號, 發現沒有, 于是系統切換到用戶態, 返回到剛剛被切換的主控制流處繼續執行下面的代碼.(注意main函數和signalhandle 之間使用不同的堆棧結構,它們之間不存在調用和被調用的關系, 是兩個獨立的控制流)
三. 相關接口函數
????1. 捕捉信號的相關接口
????????????
;????????????
????該函數是用來讀取和修改相關對信號操作的處理動作. 其中signum 是信號的編號, act 和 oact 是一個指向結構體 sigaction 的指針, act 用來存放需要修改的函數處理動作, oldact 用來保存原有的處理信號的動作, 是一個輸出型參數, 可以傳出原有的信號處理的動作. signal 函數中 signum 指的是信號的編號, handle 賦值為 SIGIGN 時表示忽略該信號, 當賦值為 SIG_DFL 時表示執行默認動作. 也可以賦值為函數指針, 表示執行用戶自定義函數, 即捕捉信號.該函數同樣不是被 main函數調用, 而是被系統調用.
????2. 掛起進程的相關接口
????????????????????????????????????????
???? 該函數用于將調用進程掛起直到有信號遞達. 如果信號的執行動作是終止信號, 則進程終止,pause 不返回 如果該信號的執行動作是忽略, 則進程繼續處于掛起, pause 不返回.如果信號的執行動作是捕捉, 則pause 返回 -1. 即pause 只有出錯時才有返回值
四. SIGCHLD信號
????該信號用于子進程退出時操作系統向父進程發送一個SIGCHLD信號,通知父進程回收子進程, 試想, 當我們將SIGCHLD信號捕捉, 然后將該信號的處理動作設為 SIG_IGN, 忽略該信號, 此時父進程將永遠不可能回收子進程, 即子進程也不會變成僵尸進程
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void handler(int sig)
{pid_t pid;while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 ){printf("wait child is sucessful\n");}printf("child is quit\n");
}
int main()
{pid_t pid;signal(SIGCHLD, handler);pid = fork();if(pid == 0){printf("I am child\n");exit(1);}else if(pid > 0){while(1){printf("father is doing somthing\n");sleep(1);}}return 0;
}
??????????????????
?????此時可以看見給父進程發送一個SIGCHLD 信號,之后, 子進程也會被回收