歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

Linux中的信號(1)

首先,我們來看一下Linux中都有那些信號:

每個信號都有一個編號和一個宏定義名稱,這些宏定義可以在signal.h中找到。

然後來看一下產生信號的條件:

1. ⽤戶在終端按下某些鍵時,終端驅動程序會發送信號給前台進程,例如Ctrl-C產生SIGINT信號,Ctrl-\產生SIGQUIT信號,Ctrl-Z產生SIGTSTP信號(可使前台進程停止,這個信號將在後面課程詳細解釋)。

2. 硬件異常產生信號,這些條件由硬件檢測到並通知內核,然後內核向當前進程發送適當的信 號。例如當前進程執行了除以0的指令,CPU的運算單元會產生異常,內核將這個異常解釋為SIGFPE信號發送給進程。再比如當前進程訪問了非法內存地址,,MMU會產生異常,內核 將這個異常解釋為SIGSEGV信號發送給進程。

3. 一個進程調用kill(2)函數可以發送信號給另一個進程。 可以用kill(1)命令發送信號 給某個進程,kill(1)命令也是調用kill(2)函數實現的,如果不明確指定信號則發送 SIGTERM信號,該信號的默認處理動作是終止進程。 當內核檢測到某種軟件條件發生時也可以通過信號通知進程,例如鬧鐘超時產生SIGALRM信號,向讀端已關閉的管道寫數據時產生 SIGPIPE信號。 如果不想按默認動作處理信號,用戶程序可以調用sigaction(2)函數告訴內核如何處理某種信號。

進程收到信號的時候不是立即處理的,在合適的時候去處理它;在處理之前,先記錄保存在自己的PCB中。

重點:只要進程退出,意味著已經處理它。

處理的方法有三種:1.忽略 2.執行該信號的默認動作 3.執行該信號的信號處理函數(catch捕捉一個信號)

通過什麼可以產生信號呢?

A. 通過終端按鍵產生信號

B.調用系統函數向進程發信號

raise函數可以給當前進程發送指定的信號(自己給自己發信號)。

abort函數使當前進程接收到SIGABRT信號而異常終止。

C.有軟件條件產生信號

信號的結構:

如果在進程解除對某信號的阻塞之前這種信號產生過多次,將如何處理?POSIX.1允許系統遞送該信號一次或多次。Linux是這樣實現的:常規信號在遞達之前產生多次只計一次,而實時信號在遞達之前產生多次可以依次放在一個隊列裡。從上圖來看,每個信號只有一 個bit的未決標志,非0即1,不記錄該信號產生了多少次,阻塞標志也是這樣表示的。因此,未決和阻塞標志可以用相同的數據類型sigset_t來存儲,sigset_t稱為信號集,這個類型可以表示每個信號的“有效”或“無效”狀態,在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處於未決狀態。

阻塞信號集也叫做當前進程的信號屏蔽字(Signal Mask),這裡的“屏蔽”理解為阻塞而不是忽略。

對於信號來說,不同的系統對其的構造略有不同,所以不能用位操作來改變他,應該用相應的信號集操作函數:

函數sigemptyset初始化set所指向的信號集,使其中所有信號的對應bit清零,表示該信號集不包含任何有效信號。

函數sigfillset初始化set所指向的信號集,使其中所有信號的對應bit置位,表示 該信號集的有效信號包括系統支持的所有信號。

注意,在使用sigset_t類型的變量之前,一定要調用sigemptyset或sigfillset做初始化,使信號集處於確定的狀態。

初始化sigset_t變量之後就可以在調用sigaddset和sigdelset在該信號集中添加或刪除某種有效信號。這四個函數都是成功返回0,出錯返回-1。

sigismember是一個布爾函數,⽤用於判斷一個信號集的有效信號中是否包含某種信號,若包含則返回1,不包含則返回0, 出錯返回-1。

信號捕捉

如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個函數,這稱為捕捉信號。

由於信號處理函數的代碼是在用戶空間的,處理過程比較復雜,如下:

1. 用戶程序注冊了SIGQUIT信號的處理函數sighandler。

2. 當前正在執行main函數,這時發生中斷或異常切換到內核態。

3. 在中斷處理完畢後要返回用戶態的main函數之前檢查到有信號SIGQUIT遞達。

4. 內核決定返回用戶態後不是恢復main函數的上下文繼續執行,而是執行sighandler函數,sighandler和main函數使用不同的堆棧空間,它們之間不存在調用和被調用的關系, 是兩個獨立的控制流程。

5. sighandler函數返回後自動執行特殊的系統調用sigreturn再次進入內核態。

6. 如果沒有新的信號要遞達,這次再返回用戶態就是恢復main函數的上下文繼續執行了。

信號的捕捉:(內核態的代碼權限特別高。。。)

上方是用戶態,下方是內核態。

Copyright © Linux教程網 All Rights Reserved