博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

多线程之信号

Posted on 2016-03-24 09:25  bw_0927  阅读(305)  评论(0)    收藏  举报

http://www.zyfforlinux.cc/2015/02/12/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BA%BF%E7%A8%8B%E5%A4%84%E7%90%86%E4%BF%A1%E5%8F%B7/

 

多线程中信号存在的问题

  • 每个线程都可以独立设置信号掩码,多线程环境下使用pthread_sigmask来设置
  • 多线程共享进程的信号
  • 所有线程共享信号处理函数(一个线程中设置信号处理函数,将会覆盖之前的信号处理函数)

解决方案

为了解决多线程中信号存在的问题,应该专门用一个线程来处理所有的信号,具体实现步骤如下:
1.创建子线程之前调用pthread_sigmask设置好信号屏蔽字(这样子进程就可以继承这些信号屏蔽字了,不处理这些信号)
2.在某个线程中调用sigwait等待被屏蔽的信号(这里是让其他线程屏蔽这些信号,只让这个线程处理这个信号)
3.sigwait返回表示信号未决,接着就可以进行信号处理了(这个时候不需要设置信号处理函数了,业务逻辑在线程中实现)

代码实现

 

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

#define handle_error_en(en,msg)\
        do{errno = en;perror(msg);exit(EXIT_FAILURE);}while(0)

//专门的线程用来处理信号
static void *sig_thread(void *arg)
{
        sigset_t *set = (sigset_t *)arg;
        int s,sig;
        for(;;)
        {
                s = sigwait(set,&sig); //等待信号,该调用返回表明信号进入未决状态,
                					   //就可以进入下面的信号处理了。
                if(s != 0)
                        handle_error_en(s,"pthread_sigmask");
                printf("signal handlinhg thread got signal %d\n",sig);
        }
}
int main(int argc,char*argv[])
{
        pthread_t thread;
        sigset_t set;
        int s;
        //屏蔽一些信号,不让其他线程接收,在指定线程等待这些信号。
        sigemptyset(&set);
        sigaddset(&set,SIGQUIT);
        sigaddset(&set,SIGUSR1);
        s = pthread_sigmask(SIG_BLOCK,&set,NULL);
        if(s != 0)
                handle_error_en(s,"pthread_sigmask");
        s = pthread_create(&thread,NULL,&sig_thread,(void*)&set);
        if(s != 0)
                handle_error_en(s,"pthread_create");
        pause();
}

  

 

=============================

https://www.cnblogs.com/cobbliu/p/5592659.html

在多线程环境下,产生的信号是传递给整个进程的,一般而言,所有线程都有机会收到这个信号,进程在收到信号的的线程上下文执行信号处理函数,具体是哪个线程执行的难以获知。也就是说,信号会随机发个该进程的一个线程

发送信号给进程,哪个线程会收到?APUE说,在多线程的程序中,如果不做特殊的信号阻塞处理(sigprockmask ),当发送信号给进程时,由系统选择一个线程来处理这个信号。

如果进程中,有的线程屏蔽了某个信号,而某些线程可以处理这个信号,则当我们发送这个信号给进程或者进程中不能处理这个信号的线程时,系统会将这个信号投递到进程号最小的那个可以处理这个信号的线程中去处理

默认情况下,信号将由主进程接收处理,就算信号处理函数是由子线程注册的

每个线程均有自己的信号屏蔽字,可以使用sigprocmask函数来屏蔽某个线程对该信号的响应处理,仅留下需要处理该信号的线程来处理指定的信号。

sigprocmask的行为在多线程的进程中没有定义,线程必须使用pthread_sigmask

总结:一个信号可以被没屏蔽它的任何一个线程处理

sigprocmask函数只能用于单线程,在多线程中使用pthread_sigmask函数。

每个进程都有一个信号掩码(或称为信号屏蔽字),其中定义了当前进程要求阻塞的信号集。

8 所谓阻塞,指Linux内核不向进程交付在掩码中的所有信号。于是进程可以通过修改信号掩码来暂时阻塞特定信号的交付,被阻塞的信号不会影响进程的行为直到该信号被真正交付。 

9 忽略信号不同于阻塞信号,忽略信号是指Linux内核已经向应用程序交付了产生的信号,只是应用程序直接丢弃了该信号而已。

10 sleep和nanosleep,如果没有在它调用之前设置信号屏蔽字的话,都可能会被信号处理函数打断。参见sleep和nanosleep的mannual。