APUE學習筆記 17 執行緒和訊號

2021-06-08 20:29:57 字數 3396 閱讀 9112

by:             潘雲登

date:          2009-8-22

email:         [email protected]

homepage:

對於商業目的下對本文的任何行為需經作者同意。

寫在前面

1.          本文內容對應《unix環境高階程式設計》(第2版)》第12章。

2.          總結了如何設定執行緒的訊號遮蔽字,以及如何使用專用線程進行訊號處理。

執行緒的訊號遮蔽字

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

程序中的訊號是遞送到單個執行緒的。如果訊號與硬體故障或定時器超時相關,該訊號就被傳送到引起該事件的執行緒中去,而其它的訊號則被傳送到任意乙個執行緒。但要注意,鬧鐘定時器是程序資源,並且所有的執行緒共享相同的alarm,所以程序中的多個執行緒不可能互不干擾地使用鬧鐘定時器。

執行緒必須使用pthread_sigmask函式,替代程序使用的sigprocmask,為自己設定訊號遮蔽字。兩個函式的區別在於,pthread_sigmask函式在失敗時返回錯誤碼,而不像sigprocmask那樣設定errno並返回-1。

#include

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

return: 0 if ok, error number on failure

sigwait

執行緒可以通過呼叫sigwait等待乙個或多個訊號發生。set引數指出了執行緒等待的訊號集,signop指向的整數表明接收到的訊號值。如果訊號集中的某個訊號在sigwait呼叫的時候處於未決狀態,那麼sigwait將無阻塞地返回,在返回之前,sigwait將從程序中移除那些處於未決狀態的訊號。

#include

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

return: 0 if ok, error number on failure

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

範例程式如下:

#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 err, signo;

for (;;) {

err = sigwait(&mask, &signo);  /*signo表明接收的訊號值*/

if (err != 0)

err_exit(err, "sigwait failed");

switch (signo) {

printf("/ninterrupt/n");

break;

case sigquit:

pthread_mutex_lock(&lock);

quitflag = 1;   /*修改退出標誌*/

pthread_mutex_unlock(&lock);

pthread_cond_signal(&wait);

return(0);

default:

printf("unexpected signal %d/n", signo);

exit(1);

int main(void)

int         err;

sigset_t    oldmask;

pthread_t   tid;

sigemptyset(&mask);

sigaddset(&mask, sigint);

sigaddset(&mask, sigquit);

if ((err = pthread_sigmask(sig_block, &mask, &oldmask)) != 0)

err_exit(err, "sig_block error");                /*設定執行緒訊號遮蔽字*/

err = pthread_create(&tid, null, thr_fn, 0); /*建立執行緒時,新執行緒繼承訊號遮蔽字*/

if (err != 0)

err_exit(err, "can't create thread");

pthread_mutex_lock(&lock);

while (quitflag == 0)   /*主線程並不處理sigquit訊號,而使用條件變數判斷是否退出*/

pthread_cond_wait(&wait, &lock);

pthread_mutex_unlock(&lock);

/* sigquit has been caught and is now blocked; do whatever */

quitflag = 0;

/* reset signal mask which unblocks sigquit */

if (sigprocmask(sig_setmask, &oldmask, null) < 0)

err_sys("sig_setmask error");

exit(0);

給執行緒傳送訊號

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

#include

int pthread_kill(pthread_t thread, int signo);

return: 0 if ok, error number on failure

APUE學習筆記 17 執行緒和訊號

by 潘雲登 對於商業目的下對本文的任何行為需經作者同意。寫在前面 1.本文內容對應 unix 環境高階程式設計 第 2版 第 12章。2.總結了如何設定執行緒的訊號遮蔽字,以及如何使用專用線程進行訊號處理。3.執行緒的訊號遮蔽字 每個執行緒都有自己的執行緒遮蔽字,但是訊號處理函式是程序中所有執行緒...

APUE學習筆記 執行緒

採用多執行緒模式可以採用同步程式設計,而非非同步程式設計,可以簡化程式設計 多個程序間可以很方便的共享資料 可以通過pthread self獲得自身的執行緒id。執行緒id只在程序內部唯一。新建立執行緒不能保證那個執行緒先執行,新縣城可以訪問程序的位址空間,繼承執行緒的浮點環境和訊號遮蔽字。如果任意...

APUE學習筆記 10 訊號概念

by 潘雲登 對於商業目的下對本文的任何行為需經作者同意。寫在前面 1.本文內容對應 unix 環境高階程式設計 第 2版 第 10章。2.總結了有關訊號的基本概念,包括訊號產生的原因和對訊號的處理方式。3.訊號概念 訊號是軟體中斷,提供了一種處理非同步事件的方法。每個訊號都有乙個名字,以字元 si...