Linux訊號處理機制(二) 阻塞訊號

2021-08-19 23:12:14 字數 2797 閱讀 2858

訊號在核心中一般有三種狀態:

(1)訊號遞達(delivery):實際執行訊號的處理動作稱為訊號遞達;

(2)訊號未決(pending):訊號從產生到遞達之間的狀態;

(3)訊號阻塞(block):被阻塞的訊號產生時將保持在未決狀態,直到程序解除對此訊號的阻塞,才執行遞達的動作;

注意:阻塞與忽略是不同的,只要訊號被阻塞就不會遞達,而忽略是在遞達之後可選的一種處理動作。

訊號在核心中的表示可以模擬成下圖:

每個訊號都有兩個標誌位分別表示阻塞(block)和未決(pending),還有乙個函式指標用來表示處理動作。訊號產生時,核心在pcb中設定該訊號的未決狀態,直到訊號遞達才清除該標誌。

我們對上述圖的各種狀態作以分析:

(1)sighup訊號未阻塞也未產生過(未決),當它遞達時執行預設處理動作。

(2)sigint訊號產生了,但是正在被阻塞(block),所以暫時不能被遞達。雖然它的處理動作是忽略,但是在沒有解除阻塞之前不能忽略這個訊號,因為程序仍有機會改變處理動作之後再解除阻塞。

(3)sigquit訊號未產生過,而且一旦產生就阻塞,它的處理動作是使用者自定義的訊號處理函式sighandler。

常規訊號在遞達之前產生多次只記一次,而實時訊號在遞達之前產生多次可依次放在乙個佇列裡面。

上圖中,每個訊號只有乙個位元位的未決狀態,0和1兩種,不需要記錄該訊號出現了多少次,阻塞標誌與其類似。

因此未決和阻塞標誌可以使用相同的資料型別 sigset_t 訊號集來儲存,這個型別可以表示每個訊號的有效和無效狀態。

在阻塞訊號集中:代表是否阻塞;在未決訊號集中:代表訊號是否處於未決狀態。

#include int sigemptyset(sigset_t *set);// 把訊號集清空

int sigfillset(sigset_t *set); //把訊號集全部置成1

int sigaddset(sigset_t *set, int signum); //根據signum,把訊號集中的對應為置成1

int sigdelset(sigset_t *set, int signum); //根據signum,把訊號集中的對應為置成0

int sigismember(const sigset_t *set, int signum);//判斷signum是否在訊號集中

返回值:前4個函式成功返回0,失敗返回-1。sigismember 是乙個布林函式,用於判斷乙個訊號集的有效訊號中是否包含某種訊號,若包含返回1,不包含返回0,出錯返回-1。

sigprocmask 函式可以讀取或更改程序的訊號遮蔽字(阻塞訊號集)。

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
返回值:成功返回0,失敗返回-1。

引數how:指示如何更改訊號遮蔽字,有以下三個引數可供選擇:

sig_block:set包含了我們希望新增到當前訊號遮蔽字的訊號,相當於mask = mask | set

sig_unblock:set包含了我們希望從當前訊號遮蔽字中解除阻塞的訊號,相當於mask = mask & ~set

sig_setmask:設定當前訊號遮蔽字為set所指向的值,相當於mask = set

引數set:表示你要指定的訊號集合。

引數oldset:返回舊的阻塞訊號集。

如果oldset是非空指標,則讀取程序的當前訊號遮蔽字通過oldset引數傳出。如果set是非空指標,則更改程序的訊號遮蔽字。如果oldset和set都是非空指標,則將原來的訊號遮蔽字備份到oldset裡面,然後再根據set和how引數更改訊號遮蔽字。

如果呼叫 sigprocmask 解除了對當前若干未決訊號的阻塞,則在sigprocmask返回前,至少將其中乙個訊號遞達。

sigpending函式用來讀取當前程序的訊號未決集,通過set引數傳出。

int sigpending(sigset_t *set);//讀取當前程序的訊號未決集
返回值:成功返回0,出錯返回-1。

sigpending讀取當前程序的未決訊號集,通過set引數傳出,呼叫成功返回0,失敗返回-1。

我們通過例子來驗證一下程序阻塞:

從上圖結果可以看出,我們每隔一秒列印一遍32位訊號的未決狀態,由於我們阻塞了sigint訊號,按ctrl+c會使sigint訊號處於未決狀態。因為我們沒有阻塞sigquit訊號,因此使用ctrl+\也可以終止程式。

下面我們在寫乙個程式,當我們按下ctrl-c的時候對2號訊號置1進入未決狀態,5秒之後阻塞訊號集,看2號訊號是否從未決狀態到達遞達狀態。

#include#include#includevoid printf_pending(sigset_t *pending)

else

} printf("\n");

}void handler(int sig)

int main()

} return 0;

}

執行結果如下圖:

從結果可以看出,pending表的2號訊號從1變成了0,即說明2號訊號已經遞達。

Linux訊號處理機制

程式錯誤 除零,非法記憶體訪問 外部訊號 終端ctrl c產生sgint訊號,定時器到期產生sigalrm 顯式請求 kill函式允許程序傳送任何訊號給其他程序或程序組。目前linux支援64種訊號。訊號分為非實時訊號 不可靠訊號 和實時訊號 可靠訊號 兩種型別,對應於 linux 的訊號值為 1 ...

Linux中的訊號處理機制 二

linux中的訊號處理機制 一 訊號排隊對於每乙個目標程序,核心會用乙個位圖 bitmap 來記錄訊號的處理狀態。如果乙個訊號還未被目標程序處理,那麼它就是掛起 未決 pending 的狀態。核心在向目標程序遞送訊號時,會檢視程序對應的bitmap中,該訊號對應的bit是否有掛起的訊號。如果當前有掛...

LINUX訊號處理機制的原理

訊號處理機制的原理 核心給乙個程序傳送軟中斷訊號的方法,是在程序所在的程序表項的訊號域設定對應於該訊號的位。這裡要補充的是,如果訊號傳送給乙個正在睡眠的程序,那麼要 看該程序進入睡眠的優先順序,如果程序睡眠在可被中斷的優先順序上,則喚醒程序 否則僅設定程序表中訊號域相應的位,而不喚醒程序。這一點比較...