我们在线程基础中说过,每个线程都有自己的signal mask(信号屏蔽字),也就是单个线程可以筛选某些信号。
thread中的信号处理very similar to 进程中的信号处理,比如:
(1)pthread_sigmask vs sigprocmask
不过需要注意的是,pthread_sigmask失败时直接返回错误码;而sigprocmask失败时设置errno并返回-1;
(2)pthread_kill vs kill
还记得吗?“kill is not kill”,发送信号。
(3)sigwait vs sigsuspend
这两个看起来很突兀,对应到书上是12-16(线程)与10-23(进程)。sigsuspend用在process中,是suspend一个进程并等待一个信号的到来;sigwait用在线程中,在12-16中,我们不用signal handler中断main thread(10-23中使用其中断进程的),而是有专门的thread来处理信号。关于signalwait的使用细节,可以看这里:【http://man7.org/linux/man-pages/man3/sigwait.3.html】【http://blog.csdn.net/wozaiwogu/article/details/4361456】。
好啦,我们看代码以详细了解线程的信号处理:
#include "apue.h" #include <pthread.h> int quitflag; sigset_t mask; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER; void * thr_fn(void *arg) { int err, signo; for(; ;) { err = sigwait(&mask, &signo); if(err != 0) err_exit(err, "sigwait failed!"); switch(signo) { case SIGINT: printf("\n interrupt\n"); break; case SIGQUIT: pthread_mutex_lock(&lock); quitflag = 1; pthread_mutex_unlock(&lock); pthread_cond_signal(&waitloc); return(0); default: printf("unexpected signal\n"); exit(1); } } } int main(void) { int err; sigset_t oldmask; pthread_t tid; /* Set the signal set */ sigemptyset(&oldmask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGQUIT); if((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0) err_exit(err, "SIG_BLOCK error"); /* Create a new thread */ err = pthread_create(&tid, NULL, thr_fn, 0); if(err !=0) err_exit(err, "can't create thread"); /* using mutex and condition variables to handle a signal */ pthread_mutex_lock(&lock); while(quitflag == 0) pthread_cond_wait(&waitloc, &lock); pthread_mutex_unlock(&lock); /* SIGQUIT has been caught and is now blocked; do whatever */ quitflag = 0; if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); exit(0); }
本程序中使用了条件变量来进行同步信号处理,处理的信号包括SIGINT(ctrl+c)和SIGQUIT(ctrl+\);接到SIGINT时输出提示,直到接到SIGQUIT时退出。我们主要看main函数,注意以下几点:
(1)signal set 和 signal mask的使用
以前说过,有两个信号是不能被忽略的:SIGSTOP和SIGKILL,原因是它们给kernel或superuser提供了可靠的停止或终止方法;
(2)还记不记得condition variable的使用“模板”?
case SIGQUIT 和 main中的交互处理方式;
(3)sigwait、pthread_sigmask与sigprocmask的使用。
下面是长长的分割线~
————————————————————————————————————————
好啦,关于线程,我们就讲那么多,下面看deamon!