訊號屏蔽字在多線程環境下的應用

來源:互聯網
上載者:User

1. 訊號屏蔽字和sigprocmask函數

每個進程都有一個訊號屏蔽字(signal mask),它規定了當前要阻塞遞送到該進程的訊號集。對於每個可能的訊號,該屏蔽字中都有一位與之對應。

進程可以調用sigprocmask函數來擷取或設定這個訊號屏蔽字。

2. 訊號的產生、遞送、未決狀態

1)首先,當引發訊號的事件發生時,為進程產生(generation)一個訊號(或向進程發送一個訊號)。

註:事件可以是硬體異常(例如,除以0)、軟體條件(例如,alarm計時器逾時)、終端產生的訊號或調用kill函數。

2)在產生了訊號時,核心通常在進程表中設定一個某種形式的標誌。當對訊號採取這種動作時,我們說向進程遞送(delivery)了一個訊號。

3)在訊號產生和遞送之間的時間間隔內,稱訊號是未決(pending)的。

3.  阻塞訊號的未決狀態

如1中所說,可以調用sigprocmask函數對訊號進行阻塞。

如果為進程產生了一個選擇為阻塞的訊號,而且對該訊號的動作是預設動作或捕捉該訊號,則為該進程將此訊號保持為未決狀態。直到該進程(a)對此訊號解除了阻塞(同樣通過調用sigprocmask函數),或者(b)將對此訊號的動作更改為忽略

進程可以調用sigpending函數來判斷哪些訊號是設定為阻塞並處於未決狀態的。

註:如果某個訊號在阻塞期間發生了多次。在大多數UNIX系統中,並不會對訊號遞送多次,而只會遞送一次。

總結上述知識:當一個被設定為阻塞的訊號發生時,如果進程對該訊號的動作是預設(SIG_DEF)或者捕捉(通過設定自訂處理函數)時,核心使得該訊號保持處於未決狀態,等待阻塞取消後遞送;如果進程對該訊號的動作是忽略,核心不會保留該訊號,直接忽略。

下面來看這種機制在多線程環境中的應用:

首先需要瞭解的是:在多線程環境中,每個線程都有自己的訊號屏蔽字,但是一個進程中的所有線程共用訊號的處理

即:如果在一個線程中修改了對某個訊號的處理方式,相當於修改了進程中所有線程對該訊號的處理方式。

1. 線程對訊號的屏蔽

sigprocmask函數只能用於單線程環境,在多線程環境中與之對應的函數是——pthread_sigmask。該函數與sigprocmask函數用法基本相同。

2. sigwait函數

線程可以通過調用sigwait函數等待一個或多個訊號發生。該函數的第一個參數指定了等待的訊號集合,第二個參數作為傳回值,表明實際接收到的訊號。

如果第一個參數指定的訊號集中的某個訊號在sigwait調用的時候處於未決狀態,那麼sigwait將無阻塞地返回(立即返回)

結合pthread_mask和sigwait函數,可以簡化多線程環境中訊號的處理:

為了防止某訊號中斷線程,可以

(1)將該訊號的處理方式設定為系統預設

(2)然後加到每個線程的訊號屏蔽字中(調用pthread_mask函數)

(3)安排專用線程,在該線程中調用sigwait函數等待該訊號,並在該線程中對該訊號進行處理(如果等待到的話)

如果進程中產生了某個訊號,由於在所有線程中都對該訊號進行了屏蔽,而且該訊號的處理方式為系統預設,因此該訊號將處於未決狀態。此時專用線程調用的sigwait檢測到該訊號,就會立即返回,表示等待到該訊號,進而進行相應的處理。

這種方法可用於實現守護進程對SIG_HUP訊號的捕捉。

在多線程環境中有一個問題:如果向一個進程遞送一個訊號,那麼該進程中的哪些線程會接收到這個訊號呢?

關於這個問題,《UNIX環境進階編程》一書中是這樣說的:進程中的訊號是遞送到單個線程的。如果訊號與硬體故障或計時器逾時相關,該訊號就被發送到引起該事件的線程中去,而其他的訊號則被發送到任意一個線程。

為了理解最後一句話,做了一個簡單的測試:

1)在main函數中fork一個子進程

2)在子進程中設定SIGUSR1的處理方式為捕捉,並自訂處理函數sig_usr1。處理函數的操作是列印捕捉到訊號的線程的線程ID和所在進程ID

3)在子進程中建立一個新的線程。新的線程與主線程共用sig_usr1

4)子進程的主線程和新線程中都調用pause函數等待訊號

5)父進程中,先睡眠3秒(給子進程設定訊號處理函數和建立新線程的時間),然後向子進程發送SIGUSR1

啟動並執行結果是:總是主線程接收到該訊號,而新線程不會接收到訊號。(不曉得是不是測試次數比較少的原因。。。)

對上述程式做一點修改:

1)在子進程的主線程中屏蔽SIGUSR1,然後不調用pause等待訊號,而是睡眠10秒

a)如果新線程不做修改,仍是調用pause等待訊號,那麼主線程和新線程都不會捕捉到訊號。子進程會隨著睡眠到時正常退出。

b)如果新線程不調用pause,而是調用sigwait函數等待SIGUSR1,那麼新線程會等待到函數。但是不會調用指定的訊號處理函數sig_usr1,而是繼續執行。所以當調用sigwait函數等待訊號時,需要在等待到之後重新編寫關於訊號的相應操作

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.