信号屏蔽字以及pthread_join函数

1. 概念:

信号屏蔽字就是进程中被阻塞的信号集, 这些信号不能发送给该进程, 它们在该进程中被"屏蔽"了. 后面我们会提到, 实际上它们是被阻塞了.


2. 信号屏蔽函数:

#include <signal.h>

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

成功则返回0, 出错则返回-1.
sigprocmask函数有3个参数:

how: 修改信号屏蔽字的方式. 
set: 把这个信号集设为新的当前信号屏蔽字. 如果为NULL则不改变. 
oset: 保存进程旧的信号屏蔽字. 如果为NULL则不保存. 
参数中的how可以取3个值:

sigprocmask中的how参数 how 说明 
SIG_BLOCK 修改后, 该进程新的信号屏蔽字是其当前屏蔽字和set指向的信号集的并集. 
SIG_UNBLOCK 修改后, 该进程新的信号屏蔽字是其当前屏蔽字和set指向的信号集的补集的交集. 
SIG_SETMASK 修改后, 该进程新的信号屏蔽字将被set指向的信号集的值代替


 另外要说的是, sigprocmask只为单线程定义的, 在多线程中要使用pthread_sigmask.


3. 未处理的信号:

在调用信号屏蔽的相关函数后, 被屏蔽的信号对于调用进程是阻塞的, 不能发送给调用进程, 因此是未决的. 取得这些阻塞的信号集, 可以通过调用sigpending函数.

#include <signal.h>

int sigpending(sigset_t *set);

成功则返回0, 出错则返回-1.

4. 实例:

下面通过一个简单的实例来说明这篇文章中所讲到的两个函数.

#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void sig_quit( int signo )
{
	printf("SIGQUIT is caught\n ");
	return;
}

int main()
{
	sigset_t new, old, pend;
	/*handle SIGQUIT */
	if( signal( SIGQUIT, sig_quit) == SIG_ERR )
	{
		perror("signal");
		exit(1);
	}
	
	/* add SIGQUIT to sigset */
	if( sigemptyset(&new) < 0 )
	{
		perror("sigemptyset");
	}
	if( sigaddset( &new, SIGQUIT ) < 0 )
	{
		perror("sigaddset");
	}
	
	/* Mask SIGQUIT */
	if( sigprocmask( SIG_SETMASK, &new, &old ) < 0 )
	{
		perror("sigprocmask");
		exit(1);
	}

	printf("SIGQUIT is blocked\n" );
	printf("now try Ctrl \\ \n");
	sleep(5);  /* SIGQUIT will pending */

	/* get pending */
	if( sigismember( &pend, SIGQUIT ) )
	{
		printf("SIGQUIT pending\n");
	}

	/* restore signal mask*/
	if( sigprocmask( SIG_SETMASK, &old, NULL ) < 0 )
	{
		perror("sigprocmask");
		exit(1);
	}

	printf("SIGQUIT unblocked\n");
	printf("Now try Ctrl \\ \n" );
	sleep(5);
	
	return 0;
}
这个程序在开始的时候用sigprocmask屏蔽了SIGQUIT(ctrl+\触发), 在5秒内触发的该信号将可以从sigpending中获得; 然后程序把SIGQUIT解除屏蔽(恢复以前的屏蔽字), 此时再触发该信号将调用sig_quit信号处理函数.
转载来源: http://blog.chinaunix.net/uid-23215128-id-2521283.html


#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<pthread.h>
#include<time.h>
pthread_t tid;
sigset_t set;
void myfunc()
{
 printf("hello\n");
}
void* mythread(void*p)
{
int signum;
while(1)
{
sigwait(&set,&signum);
if(SIGUSR1==signum)
myfunc();


if(SIGUSR2==signum)
{
printf("I will sleep 2 second and exit\n");
sleep(2);
break;
}
}
}

int main()
{
char tmp;
void* status;
sigemptyset(&set);
sigaddset(&set,SIGUSR1);
sigaddset(&set,SIGUSR2);
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_create(&tid,NULL,mythread,NULL);
while(1)
{
printf(":");
scanf("%c",&tmp);
if('a'==tmp)
{
pthread_kill(tid,SIGUSR1);//发送SIGUSR1,打印字符串。
}
else if('q'==tmp)
{
//发出SIGUSR2信号,让线程退出,如果发送SIGKILL,线程将直接退出。
pthread_kill(tid,SIGUSR2);
//等待线程tid执行完毕,这里阻塞。
pthread_join(tid,&status);
printf("finish\n");
break;
}
else
continue;
}
return 0;
}

运行结果:
// 如果输入a,子线程打印"hello",主程序继续等待输入;
// 如果输入q,主程序等待子程序结束。子线程打印"I will sleep 2 second and exit",并延时两秒后结束。主线程随之打印"finish",程序结束。
在前面我们提到,可以通过pthread_join()函数来使主线程阻塞等待其他线程退出,
这样主线程可以清理其他线程的环境。但是还有一些线程,更喜欢自己来清理退出的状态,
他们也不愿意主线程调用pthread_join来等待他们。我们将这一类线程的属性称为detached。
如果我们在调用pthread_create()函数的时候将属性设置为NULL,则表明我们希望所创建的线程采用默认的属性,
也就是joinable。如果需要将属性设置为detached,则参考下面的例子:

void*start_run(void*arg)
{
//dosomework
}
int main()
{
pthread_tthread_id;
pthread_attr_tattr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
pthread_create(&thread_id,&attr,start_run,NULL);
pthread_attr_destroy(&attr);
sleep(5);
exit(0);
}
在线程设置为joinable后,可以调用pthread_detach()使之成为detached。但是相反的操作则不可以。还
  有,如果线程已经调用pthread_join()后,则再调用pthread_detach()则不会有任何效果。

来源:百度百科:http://baike.baidu.com/view/2925158.htm?fr=aladdin

你可能感兴趣的:(信号屏蔽字以及pthread_join函数)