相比于进程中的信号处理,在线程中更加复杂,线程中的信号处理有如下特点:
- 每个线程都有自己的信号屏蔽字,但是信号的处理是进程中所有线程共享的。这意味着单个线程可以阻止某个信号,但是当某个线程修改了一个信号的处理行为,那么所有线程都会共享这个改变。
- 进程中的信号是递送到单个线程的。如果一个信号和硬件故障相关,那么该信号一般会被发送到引起该事件的线程中去,而其他的信号会被发送到任意的线程中。
1.屏蔽字修改函数:
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
sigprocmask函数:
用来修改进程的信号屏蔽字,但是它只能用在进程中,要修改线程的信号屏蔽字应使用函数pthread_sigmask.
pthread_sigmask函数:和使用方式和sigprocmask相同,只不过失败时返回值不像sigprocmask那样放回-1并设置errno,而是返回错误编号。
how参数:
- SIG_BLOCK ,把原来的信号屏蔽集与set的信号集,构成一个并集,变成一个新的信号屏蔽集
- SIG_SETMASK ,把原来的信号屏蔽集与set的信号集,构成一个交集,变成一个新的信号屏蔽集
- SIG_UNBLOCK ,把set的信号集变成一个新的信号屏蔽集
2.发送信号
kill将信号发送给进程,而向线程发送信号则使用函数pthread_kill.
int pthread_kill(pthread_t thread, int signo);
可以传一个0值的signo来检查线程是否存在。如果信号的默认处理动作是终止该进程,那么把信号发送给某个线程仍会杀死整个进程。
利用这个函数可以向一指定的线程发送信号
代码实例:
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int quitflag;
sigset_t mask;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //初始化互斥量
pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER; //初始化自动变量
void *pth_fn1(void *args)
{
int signo;
sigwait(&mask, &signo);
if ( SIGINT == signo )
{
printf("\n%s interrupt\n", __FUNCTION__);
}else
{
printf("没有这个信号处理\n");
}
}
int main()
{
sigset_t oldmask;
pthread_t tid1;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
pthread_sigmask(SIG_BLOCK, &mask, &oldmask); //设置屏蔽字
pthread_create(&tid1, NULL, pth_fn1, NULL);
pthread_kill(tid1, SIGINT); //向线程1发送信号
sleep(1); //wait thread return
pthread_sigmask(SIG_SETMASK, &oldmask, NULL); //还原屏蔽字
printf("ok \n");
return 0;
}
运行结果:
# ./a.out
pth_fn1 interrupt
ok
3.闹钟
闹钟定时器是进程资源,所有线程共享相同的闹钟。所以,进程中的多个线程不可能互不干扰的使用闹钟定时器。
4.sigwait函数
int sigwait(const sigset_t *restrict set, int *restrict signop);
功能:
线程可以通过调用sigwait函数等待一个或多个信号的出现。
参数:
set为要等待的信号集,返回时,signop指向的整数表明接收到的信号值。优点:
一个等待信号的线程,可以处理多个信号
缺点:
当有多个信号等待一个不是指向特定线程的信号时,进程会把它发送到任意一个等待信号的线程
由于上面的特性,当处理不是指向特定线程的信号时,一般会把所有的信号处理集中到一个线程,
既方便管理,也方便调试
实例代码:
大概意思是
- 检验信号的处理情况
- 检验当多个线程等待信号时的情况
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int quitflag;
sigset_t mask;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //初始化互斥量
pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER; //初始化自动变量
void *pth_fn(void *args)
{
int signo;
while(1){
sigwait(&mask, &signo); //等待信号
switch(signo){
case SIGINT:
printf("\n%s interrupt\n", __FUNCTION__);
break;
case SIGQUIT:
pthread_mutex_lock(&lock);
quitflag = 1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&waitloc);
return 0;
default:
printf("unexpected signal %d\n", signo);
exit(0);
}
}
}
void *pth_fn1(void *args)
{
int signo;
while(1){
sigwait(&mask, &signo);
switch(signo){
case SIGINT:
printf("\n%s interrupt\n", __FUNCTION__);
break;
case SIGQUIT:
pthread_mutex_lock(&lock);
quitflag = 1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&waitloc);
return 0;
default:
printf("unexpected signal %d\n", signo);
exit(0);
}
}
}
int main()
{
sigset_t oldmask;
pthread_t tid;
pthread_t tid1;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
pthread_sigmask(SIG_BLOCK, &mask, &oldmask); //设置屏蔽字
pthread_create(&tid, NULL, pth_fn, NULL);
pthread_create(&tid1, NULL, pth_fn1, NULL);
pthread_mutex_lock(&lock);
while(quitflag == 0)
pthread_cond_wait(&waitloc, &lock); //等待自动变量
pthread_mutex_unlock(&lock);
quitflag = 0;
pthread_sigmask(SIG_SETMASK, &oldmask, NULL); //还原屏蔽字
printf("ok \n");
return 0;
}
运行结果:
# ./a.out
^C
pth_fn interrupt
^C
pth_fn interrupt
^C
pth_fn interrupt
^\ok
root@:/home/#