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信号处理函数.
#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