1. 程式人生 > 其它 >第六章 訊號和訊號處理

第六章 訊號和訊號處理

第六章 訊號和訊號處理

6.1 訊號和中斷

  • 中斷:是從I/O裝置或協處理器傳送到CPU的外部請求,他將CPU從正常執行轉移到中斷處理。

  • 程序中斷:這類終端是傳送給程序的終端。當某程序正在執行時,可能會收到三個不同來源的終端:

    (1)來自硬體的中斷:終端、間隔定時器的“Ctrl+C”組合鍵等。

    (2)來自其他程序的中斷

    (3)自己造成的中斷

  • 硬體中斷:這類中斷時傳送給處理器或CPU的訊號。

6.2 Umix/Linux中的訊號處理

Unix/Linux支援31中不同的訊號,每種訊號在signal.h檔案中都有定義。

訊號的來源

  • 來自硬體中斷的訊號:在執行過程中,一些硬體中斷被轉換為訊號傳送給程序硬體訊號示例

    • 中斷鍵(Ctrl+C),它產生一個SIGINT(2)訊號。
    • 間隔定時器,當他的時間到期時,會生成一個SIGALRM(14)、SIGTALRM(26)或SIGPROF(27)訊號。
    • 其他硬體錯誤,如匯流排錯誤、IO陷進
  • 來自異常的訊號:常見的陷阱訊號有SIGFPE(8),表示浮點異常(除以0),最常見也是最可怕的時SIGSEGV(11),表示段錯誤

  • 來自其他程序的訊號:程序可以使用kill(pid,sig)系統呼叫向pid標識的目標程序傳送訊號。

程序PROC結構體中的訊號

每個程序PROC都有一個32位 向量,用來記錄傳送給程序的訊號。在位向量中,每一位(0位除外)代表一個訊號編號。此外,他還有一個訊號MASK位向量,用來遮蔽相信的訊號。

訊號處理函式

每個程序PROC都有一個訊號處理陣列int sig[32]。sig[32]陣列的每個條目都指定了如何處理相應的訊號,其中0表示 DEFault(預設),1表示IGNore(忽略),其他非零值表示使用者模式下預先安裝的訊號捕捉(處理)函式。圖給出了訊號位向量、遮蔽位向量和訊號處理函式。

如果訊號位向量中的位1為1,則會生成一個訊號I或將其傳送給程序。如果遮蔽位向量的位1為1,則訊號會被阻塞或遮蔽。否則,訊號未被阻塞。只有當訊號存在並且未被阻塞時,訊號才會生效或傳遞給程序。當核心模式下的程序發現一個未阻塞訊號時,會將訊號位清除為0,並嘗試通過訊號處理陣列中的處理函式來處理該訊號。0表示 DEFault,1表示IGNore,其他數值表示使用者空間內預先安裝的捕捉函式。

安裝訊號捕捉函式

程序可以使用系統呼叫

int r = signal(int signal_number,voide *handler);

來修改選定訊號編號的處理函式,(19)和(9)除外,他們不能修改。

signal()系統呼叫在所有類Unix系統中均可用,但它有一些不理想的特點。
(1)在執行已安裝的訊號捕捉函式之前,通常將訊號處理函式重置為DEFault。為捕捉下次出現的相同訊號,必須重新安裝捕捉函式。這可能會導致下一個訊號和訊號處理函式重新安裝之間出現競態條件。相反,sigaction()在執行當前捕捉函式時會自動阻塞下一個訊號,因此不會出現競態條件。
( 2 ) signal()不能阻塞其他訊號。必要時,使用者必須使用sigprocmask()顯式地阻塞或解鎖其他訊號。相反,sigaction(可以指定要阻塞的其他訊號。
( 3 ) signal()只能向捕捉函式傳送一個訊號編號。sigaction()可以傳輸關於訊號的其他資訊。

signal()系統呼叫在所有類Unix系統中均可用,但它有一些不理想的特點。
(1)在執行已安裝的訊號捕捉函式之前,通常將訊號處理函式重置為DEFault。為捕捉下次出現的相同訊號,必須重新安裝捕捉函式。這可能會導致下一個訊號和訊號處理函式重新安裝之間出現競態條件。相反,sigaction()在執行當前捕捉函式時會自動阻塞下一個訊號,因此不會出現競態條件。
( 2 ) signal()不能阻塞其他訊號。必要時,使用者必須使用sigprocmask()顯式地阻塞或解鎖其他訊號。相反,sigaction(可以指定要阻塞的其他訊號。
( 3 ) signal()只能向捕捉函式傳送一個訊號編號。sigaction()可以傳輸關於訊號的其他資訊。

( 4 ) signal()可能不適用於多執行緒程式中的執行緒。sigaction()適用於執行緒。
(5)不同Unix版本的signal()可能會有所不同。sigaction()採用的是POISX標準,可移植性更好。

sigaction()系統呼叫

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

6.3訊號處理步驟

(1)當某程序處於核心模式時,會檢查訊號並處理未完成的訊號。如果某訊號有使用者安裝的捕捉函式,該程序會先清除訊號,獲取捕捉函式地址,對於大多數陷阱訊號,則將已安裝的捕捉函式重置為DEFault。然後,它會在使用者模式下返回,以執行捅捉函式,以這種方式篡改返回路徑。當捕捉函式結束時,它會返回到最初的中斷點,即它最後進入核心模式的地方。因此,該程序會先遷回執行捕捉函式,然後再恢復正常執行。

(2)重置使用者安裝的訊號捕捉函式:使用者安裝的陷阱相關訊號捕捉函式用於處理使用者程式碼中的陷阱錯誤。由於捕捉函式也在使用者模式下執行,因此可能會再次出現同樣的錯誤。如果是這樣,該程序最終會陷入無限迴圈,一直在使用者模式和核心模式之間跳躍。為了防止這種情況,Unix核心通常會在允許程序執行捕捉函式之前先將處理函式重置為DEFault。這意味著使用者安裝的捕捉函式只對首次出現的訊號有效。若要捕捉再次出現的同一訊號,則必須重新安裝捕捉函式。但是,使用者安裝的訊號捕捉函式的處理方法並不都一樣,在不同 Unix版本中會有所不同。例如,在 BSD Unix中,訊號處理函式不會被重置,但是該訊號在執行訊號捕捉函式時會被阻塞。感興趣的讀者可參考關於Lioux訊號和 sigaction函式的手冊頁,以瞭解更多詳細資訊。

(3)訊號和喚醒:在Unix/Linux核心中有兩種SLEEP程序;深度休眠程序和淺度休眠程序。前一種程序不可中斷,而後一種程序可由訊號中斷。如果某程序處於不可中斷的SLEEP狀態,到達的訊號(必須來自硬體中斷或其他程序)不會喚醒程序。如果它處於可中斷的SLEEP狀態,到達的訊號將會喚醒它。例如,當某程序等待終端輸入時,它會以低優先順序休眠,這種休眠是可中斷的,SIGINT這類訊號即可喚醒它。

6.4Linux中的IPC

IPC是指用於程序間通訊的機制。在Linux中,IPC包含以下部分

1)管道和FIFO

2)訊號

3)System V IPC

4)POSIX訊息佇列

5)執行緒同步機制

6)套接字

在openeuler中程式設計

例6.1:sigaction()

原始碼

執行結果

遇到的問題

問題:

在執行上述程式碼的過程中,使用

kill -s 15 PID;

無法結束程序,始終提示無法找到PID對應的程序。

解決辦法

通過反覆搜尋資料也沒發現問題所在,最終在看課笨的過程中發現,書中給的程式碼有一定的錯誤,需要自行修改以下才能成功顯示程序對應的PID。

程式碼連結

https://gitee.com/lhp666/linux/tree/master