二 Linux進程間通信( 五 )


信號的捕獲一個進程收到一個信號的時候,可以用以下的方法進行處理:
(1)執行系統默認動作:對大多數信號來說,系統默認動作就是來終止進行 。
(2)忽略此信號(丟棄):接收到此信號后沒有任何動作
(3)執行自定義信號處理函數(捕獲):用戶定義的信號處理函數處理該信號
注意:SIGKILL和SIGSTOP不能更改信號的處理方式 , 因為它們向用戶提供了一種使進程終止的可靠方法 。
信號捕捉的過程先思考一個問題:信號是什么時候被進程處理的?
首先,不是立即被處理的 。而是在合適的時候 , 這個合適的時候,具體指的是進程從用戶態切換回內核態時進行處理
這句話如何理解,什么是用戶態?什么是內核態?

  • 用戶態: 處于?戶態的 CPU 只能受限的訪問內存,用戶的代碼,并且不允許訪問外圍設備,權限比較低
  • 內核態: 處于內核態的 CPU 可以訪問任意的數據,包括外圍設備,?如?卡、硬盤等,權限比較高
注意: 操作系統中有一個cr寄存器來記錄當前進程處于何種狀態
進程空間分為用戶空間和內核空間 。此前我們介紹的頁表都是用戶級頁表 , 其實還有內核級頁表 。進程的用戶空間是通過用戶級頁表映射到物理內存上,內核空間是通過內核級頁表映射到物理內存上,如下面簡圖所示:
二 Linux進程間通信

文章插圖
二 Linux進程間通信

文章插圖
  • 當進程運行在內核空間時就處于內核態,而進程運行在用戶空間時則處于用戶態 。
  • 最高 1G 的內核空間是被所有進程共享的!
進程有不同的用戶空間,但是只有一個內核空間,不同進程的用戶空間的代碼和數據是不一樣的,但是內核空間的代碼和數據是一樣的 。上面這些主要是想說:進程處于用戶態訪問的是用戶空間的代碼和數據 , 進程處于內核態,訪問的是內核空間的代碼和數據 。
信號捕捉的整個過程:
二 Linux進程間通信

文章插圖
從上面的圖可以看出,進程是在返回用戶態之前對信號進行檢測,檢測pending位圖,根據信號處理動作,來對信號進行處理 。這個處理動作是在內核態返回用戶態后進行執行的,所以這里也就回答了開始提出的那一個問題了 。
sigaction函數#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);功能:檢查或修改指定信號的設置(或同時執行兩種操作)參數:signum:要操作的函數act:要設置的對信號的新處理方式(傳入方式)oldact:原來對信號的處理方式(傳出參數)如果act指針非空,則要改變指定信號的處理(設置),如果oldact指針非空,則系統將此前指定信號的處理方式入oldact返回值:成功:0失敗:-1struct sigaction結構體:
struct sigaction { void(*sa_handler)(int);//舊的信號處理函數指針void(*sa_sigaction)(int, siginfo_t *, void *);//新的信號處理函數指針sigset_tsa_mask;//信號阻塞集intsa_flags;//信號處理的方式void(*sa_restorer)(void);//已經棄用};(1)sa_handler、sa_sigaction:信號處理函數指針 , 和signal里面的函數指針用法是一樣的,根據情況給兩個指針賦值 。
?a)SIG_IGN:忽略該信號
?b)SIG_DFL:執行系統默認的動作
?c)處理函數名:自定義信號處理函數
(2)sa_mask:信號阻塞集,在執行信號處理函數的時候 , 用來臨時的屏蔽信號
(3)sa_flags:用于指定信號處理的行為,通常設置為0,表示使用默認的屬性 。它可以是一下值的“按位”或“組合”:
  • SA_NOCLDSTOP:使父進程在它的子進程暫?;蚶^續運行時不會收到SIGCHLD信號 。
  • SA_NOCLDWAIT:使父進程在它的子進程退出的時候不會收到SIGCHLD信號,這時子進程如果退出也不會成為僵尸進程 。
  • SA_NODEFER:使對信號的屏蔽無效,即在信號處理函數執行期間仍能發出整個信號 。
  • SA_RESETHAND:信號處理之后重新設置為默認的處理方式 。
  • SA_SIGINFO:使用sa_sigaction成員而不是sa_handler作為信號處理函數 。
代碼示例:
#include <stdio.h>#include <unistd.h>#include <signal.h>void handler(int signo){printf("catch a signal: %d\n", signo);}int main(){struct sigaction act, oact;act.sa_flags = 0;// 選項 設置為0sigfillset(&act.sa_mask);act.sa_handler = handler;// 對2號信號修改處理動作sigaction(2, &act, &oact);while (1){raise(2);sleep(1);}return 0;}

推薦閱讀