執行緒控制之執行緒和訊號

2022-05-04 20:06:17 字數 2599 閱讀 7641

每個執行緒都有自己的訊號遮蔽字,但是訊號的處理是程序中所有執行緒共享的。這意味著儘管單個執行緒可以阻止某些訊號,但當執行緒修改了與某個訊號相關的處理行為以後,所有的執行緒都必須共享這個處理行為的改變。

程序中的訊號是遞送到單個執行緒的。如果訊號與硬體故障或計時器超時相關,該訊號就被傳送到引起該事件的執行緒中去,而其他的訊號則被傳送到任意乙個執行緒。

中討論了程序如何使用sigprocmask來阻止訊號傳送。sigpromask的行為在多執行緒的程序中並沒有定義,執行緒必須使用pthread_sigmask

#include int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);

返回值:若成功則返回0,否則返回錯誤編號

執行緒可以通過呼叫sigwait等待乙個或多個訊號發生。

#include int sigwait(const sigset_t *restrict set, int *restrict signop);

返回值:若成功則返回0,否則返回錯誤編號

set引數指出了執行緒等待的訊號集,signop指向的整數將作為返回值,表明訊號編號。

如果訊號集中的某個訊號在sigwait呼叫的時候處於未決狀態,那麼sigwait將無阻塞地返回,在返回之前,sigwait將從程序中移除那些處於未決狀態的訊號。為了避免錯誤動作發生,執行緒在呼叫sigwait之前,必須阻塞那些它正在等待的訊號。sigwait函式會自動取消訊號集的阻塞狀態,直到有新的訊號被遞送。在返回之前,sigwait將恢復執行緒的訊號遮蔽字。如果訊號在sigwait呼叫的時候沒有被阻塞,在完成對sigwait呼叫之前會出現乙個時間窗,在這個時間視窗期,某個訊號可能在完成sigwait呼叫之前就被遞送了。

使用sigwait的好處在於它可以簡化訊號處理,允許把非同步產生的訊號用同步的方式處理。為了防止訊號中斷執行緒,可以把訊號加到每個執行緒的訊號遮蔽字中,然後安排專用線程作訊號處理。這些專用線程可以進行函式呼叫,不需要擔心在訊號處理程式中呼叫哪些函式是安全的,因為這些函式呼叫來自正常的執行緒環境,而非傳統的訊號處理程式,傳統訊號處理程式通常會中斷執行緒的正常執行。

如果多個執行緒在sigwait呼叫時,等待的是同乙個訊號,這時就會出現執行緒阻塞。當訊號遞送的時候,只有乙個執行緒可以從sigwait中返回。如果訊號**獲(例如程序通過使用sigaction建立了乙個訊號處理函式),而且執行緒正在sigwait呼叫中等待同乙個訊號,那麼這時將由作業系統實現來決定以何種方式遞送訊號。在這種情況下,作業系統實現可以讓sigwait返回,也可以啟用訊號處理程式,但不可能出現兩者皆可的情況。

要把訊號傳送到程序,可以呼叫kill(見要把訊號傳送到執行緒,可以呼叫pthread_kill。

#include int pthread_kill(pthread_t thread, int

signo);

返回值:若成功則返回0,否則返回錯誤編號

可以傳乙個0值的signo來檢查執行緒是否存在。如果訊號的預設處理動作是終止該程序,那麼把訊號傳遞給某個執行緒仍然會殺掉整個程序。

注意鬧鐘定時器是程序資源,並且所有的執行緒共享相同的alarm。所以程序中的多個執行緒不可能互不干擾(或互不合作)地使用鬧鐘定時器。

例項

程式清單12-6 同步訊號處理

#include "

apue.h

"#include

int quitflag; /*

set nonzero by thread

*/sigset_t mask;

pthread_mutex_t

lock =pthread_mutex_initializer;

pthread_cond_t wait =pthread_cond_initializer;

void *thr_fn(

void *arg)

}}int

main(

void

)

這裡並不讓訊號處理程式中斷主控執行緒,而是由專門的獨立控制線程進行訊號處理。改動quitflag的值是在互斥量的保護下進行的,這樣主控執行緒不會在呼叫pthread_cond_signal時錯失喚醒呼叫。在主控執行緒中使用相同的互斥量來檢查標誌的值,並且原子地釋放互斥量,等待條件的發生。

注意在主線程開始時阻塞sigint和sigquit。當建立執行緒進行訊號處理時,新建執行緒繼承了現有的訊號遮蔽字。因為sigwait會解除訊號的阻塞狀態,所以只有乙個執行緒可以用於訊號的接收。這使得對主線程進行編碼時不必擔心來自這些訊號的中斷。

執行這個程式可以得到與程式10-16類似的輸出結果:

interrupt        鍵入中斷字元

interrupt 再次鍵入中斷字元

interrupt 再一次

用結束字元終止

本篇博文內容摘自《unix環境高階程式設計》(第二版),僅作個人學習記錄所用。關於本書可參考:

執行緒控制之執行緒和I O

中介紹了pread和pwrite函式,這些函式在多執行緒環境下是非常有幫助的,因為程序中的所有執行緒共享相同的檔案描述符。考慮兩個執行緒,在同一時間對同一檔案描述符進行讀寫操作。執行緒a lseek fd,300,seek set read fd,buf1,100 執行緒b lseek fd,700...

Linux之執行緒控制

執行緒控制 由於執行緒是後來才引用進來的,因此,在編譯鏈結時需要加 lpthread來引入外部庫 posix 建立執行緒 include 函式原型 int pthread create pthread t thread,const pthread attr t attr,void start rou...

執行緒控制 join執行緒

在我們做專案的時候時常會有這樣的一種需求 我們需要執行兩個方法,乙個方法要等另乙個方法執行完才能執行,這樣的狀況放到多執行緒中要怎麼實現呢?今天就來看看多執行緒中的join方法。我們的均方法通常是把乙個大問題分成許多小問題,每個小問題分配乙個執行緒,當所有的小問題都得到處理後,在呼叫主線程來進一步操...