Posted on 2013-01-18 16:52
鑫龍 閱讀(727)
評論(0) 編輯 收藏 引用 所屬分類:
linux編程
在Linux的多線程中使用信號機制,與在進程中使用信號機制有著根本的區別,可以說是完全不同。在進程環境中,對信號的處理是,先注冊信號處理函數,當信號異步發生時,調用處理函數來處理信號。它完全是異步的(我們完全不知到信號會在進程的那個執行點到來!)。然而信號處理函數的實現,有著許多的限制;比如有一些函數不能在信號處理函數中調用;再比如一些函數read、recv等調用時會被異步的信號給中斷(interrupt),因此我們必須對在這些函數在調用時因為信號而中斷的情況進行處理(判斷函數返回時 enno 是否等于 EINTR)。
但是在多線程中處理信號的原則卻完全不同,它的基本原則是:將對信號的異步處理,轉換成同步處理,也就是說用一個線程專門的來“同步等待”信號的到來,而其它的線程可以完全不被該信號中斷/打斷(interrupt)。這樣就在相當程度上簡化了在多線程環境中對信號的處理。而且可以保證其它的線程不受信號的影響。這樣我們對信號就可以完全預測,因為它不再是異步的,而是同步的(我們完全知道信號會在哪個線程中的哪個執行點到來而被處理!)。而同步的編程模式總是比異步的編程模式簡單。其實多線程相比于多進程的其中一個優點就是:多線程可以將進程中異步的東西轉換成同步的來處理。
1. sigwait函數:
sigwait等一個或者多個指定信號發生。
它所做的工作只有兩個:第一,監聽被阻塞的信號;第二,如果所監聽的信號產生了,則將其從未決隊列中移出來(這里實時信號和非實時信號又有區別,體現在取出的順序等,具體自己取網上查,這里不再詳述)。sigwait并不改變信號掩碼的阻塞與非阻塞狀態。
在POSIX標準中,當進程收到信號時,如果是多線程的情況,我們是無法確定是哪一個線程處理這個信號。而sigwait是從進程中pending的信號中,取走指定的信號。這樣的話,如果要確保sigwait這個線程收到該信號,那么所有線程含主線程以及這個sigwait線程則必須block住這個信號,因為如果自己不阻塞就沒有未決狀態(阻塞狀態)信號,別的所有線程不阻塞就有可能當信號過來時,被其他的線程處理掉。
記?。?/span>
在多線程代碼中,總是使用sigwait或者sigwaitinfo或者sigtimedwait等函數來處理信號。
而不是signal或者sigaction等函數。因為在一個線程中調用signal或者sigaction等函數會改變所以線程中的
信號處理函數。而不是僅僅改變調用signal/sigaction的那個線程的信號處理函數。
2. pthread_sigmask函數:
每個線程均有自己的信號屏蔽集(信號掩碼),可以使用pthread_sigmask函數來屏蔽某個線程對某些信號的
響應處理,僅留下需要處理該信號的線程來處理指定的信號。實現方式是:利用線程信號屏蔽集的繼承關系
(在主進程中對sigmask進行設置后,主進程創建出來的線程將繼承主進程的掩碼)
3. pthread_kill函數:
在多線程程序中,一個線程可以使用pthread_kill對同一個進程中指定的線程(包括自己)發送信號。注意在多線程中
一般不使用kill函數發送信號,因為kill是對進程發送信號,結果是:正在運行的線程會處理該信號,如果該線程沒有
注冊信號處理函數,那么會導致整個進程退出。
記?。?/span>調用sigwait同步等待的信號必須在調用線程中被屏蔽,并且通常應該在所有的線程中被屏蔽(這樣可以保證信號絕不會被送到除了調用sigwait的任何其它線程),這是通過利用信號掩碼的繼承關系來達到的。