apue学习第十九天(2)——线程与信号

我们在线程基础中说过,每个线程都有自己的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!


你可能感兴趣的:(apue学习第十九天(2)——线程与信号)