当线程被创建时,它会继承进程的信号掩码,这个掩码就会变成线程私有的,所以我们可以设置进程的信号掩码,使其在当前进程创建的线程都会屏蔽信号。多个线程是共享进程的地址空间,每个线程对信号的处理函数是相同的,即如果某个线程修改了与某个信号相关的处理函数后,所在进程中的所有线程都必须共享这个处理函数的改变。这样如果一个线程选择忽略某个信号,而其他的线程可以恢复信号的默认处理行为,或者为信号设置一个新的处理程序,从而可以撤销上述线程的信号选择,即后来线程的处理设置会覆盖前者线程的处理设置。
每个信号只会被传递给一个线程,即进程中的信号是传递到单个线程的,传递给哪个线程是不确定的。如果信号与硬件故障或计时器超时相关,该信号就被发送到引起该事件的线程中去。但是alarm 定时器是所有线程共享的资源,所以在多个线程中同时使用alarm 还是会互相干扰。
在进程中可以调用 sigprocmask 来阻止信号发送,但在多线程的进程中它的行为并没有定义,它可以不做任何事情。在主线程中调用pthread_sigmask 使得所有线程都阻塞某个信号,也可以在某个线程中调用它来设置自己的掩码。
/* 线程与信号 */ /* * 函数功能:设置线程的信号屏蔽字; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ #include <signal.h> int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset); /* * 说明: * 该函数的功能基本上与前面介绍的在进程中设置信号屏蔽字的函数sigprocmask相同; */ /* * 函数功能:等待一个或多个信号发生; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ int sigwait(const sigset_t *set, int *signop); /* * 说明: * set参数指出线程等待的信号集,signop指向的整数将作为返回值,表明发送信号的数量; */ /* * 函数功能:给线程发送信号; * 返回值:若成功则返回0,否则返回错误编码; * 函数原型: */ int pthread_kill(pthread_t thread, int signo); /* * 说明: * signo可以是0来检查线程是否存在,若信号的默认处理动作是终止整个进程,那么把信号传递给某个线程仍然会杀死整个进程; */
测试程序:
#include "apue.h" #include <pthread.h> #include <signal.h> int quitflags; sigset_t mask; //初始化互斥量、条件变量 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t wait = PTHREAD_COND_INITIALIZER; void *thr_fun(void *arg); int main(void) { int err; sigset_t oldmask; pthread_t tid; //初始化信号集,添加两个信号SIGINT、SIGQUIT sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGQUIT); //在主线程设置信号屏蔽字,使得所以线程都阻塞信号集的信号 err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask); if(err != 0) err_quit("SIG_BLOCK error: %s\n", strerror(err)); //创建新的线程 err = pthread_create(&tid, NULL, thr_fun, 0); if(err != 0) err_quit("can't create thread: %s\n", strerror(err)); //对主线程进行加锁 pthread_mutex_lock(&lock); //等待条件变量为真 while(quitflags == 0) pthread_cond_wait(&wait, &lock); //对主线程解锁操作 pthread_mutex_unlock(&lock); quitflags = 0; //打开信号屏蔽字 if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); exit(0); } void *thr_fun(void *arg) { int err, signo; for(; ;) { //在新建线程中等待信号发生 err = sigwait(&mask, &signo); if(err != 0) err_quit("sigwait error: %s\n", strerror(err)); switch(signo) { case SIGINT: printf("\ninterrupt\n"); break; case SIGQUIT: pthread_mutex_lock(&lock); quitflags = 1; pthread_mutex_unlock(&lock); pthread_cond_signal(&wait); return(0); default: printf("unexpected signal %d\n", signo); exit(1); } } }
输出结果:
^C interrupt ^C interrupt ^C interrupt ^\
《UNIX高级环境编程》