当前位置: 首页 > Linux kernrl, 进程/线程 > 正文

线程异步信号

先容我吐槽一下《Linux C 编程实战》给这本跪了,错误就不说了,且当印刷问题吧,里边讲的东西太笼统。。。。。。。。。。。。。。。

Unix下信号是个很强大的存在,但是可重入性是个比较棘手的问题,昨天在developerworks看的[那篇文章](http://www.ibm.com/developerworks/cn/linux/l-reent.html)给出了五个保证可重入性的经验。除了这个以外,APUE给出了通过子线程来达到异步信号处理同步化的目的,从而不用再考虑可重入性问题了,非可重入性函数也可以随便用,因为我们开了一个子线程专门来处理信号。从此,妈妈再也不用担心我处理不好可重入性了,但是这个技能限于Unix,囧tz。因为LInux线程是用进程来实现的,不过就是调用了clone(2)来实现进程之间的资源共享,所以除非以进程组为单位来进行信号处理,比如在终端运行时,终端发送的信号可以传给整个进程组,这时效果跟Unix一样,但是用kill(2)给主进程发送信号时就达不到Unix下的效果了。


处理过程如下,主线程为了等待自己要处理的信号,必须先阻塞要等待的信号(这是一种多么虐心的爱啊,不过矛盾中带着统一的影子,这个世界不是离散的,没有绝对的二分,真心给搞哲学的跪了,我太喜欢哲学了,而且是唯物主义,你们不要基于乱七八糟的意识形态黑老马了,我爱他),比如要等待SIGQUIT和SIGINT,那么先要在主线程中阻塞掉这俩信号,基本流程如下:
`c
sigset_t mask;
int quit_flag;//SIGQUIT信号被捕捉到的标志,由捕捉SIGQUIT信号的子线程把该变量设置为非零值

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t wait = PTHREAD_COND_INITIALIZER;

//这个函数在新开的子线程中使用
void thr_fn(void *arg) {
    int signo;//用于保存sigwait捕获的信号
    for (;;) {
        //大侠出场,它被调用之后,立马会把mask中被阻塞的信号给解除阻塞,然后安静的等待她们的到来
        if (sigwait(&mask, &signo) != 0)
             exit(102);//出错啦
        switch (signo) {
        case SIGINT://抓到SIGINT
            printf(“interrupt!\n”);//妈妈可以放心我在这里随意调用非可重入的ISO 标准IO了
            break;
         case SIGQUIT://抓到SIGQUIT
             pthread_mutex_lock(&lock);
             quit_flag = 1;
             pthread_mutex_unlock(&lock);
             pthread_cond_signal(&wait);
             return(0);
         default:
             printf(“unexpected signal %d\n”, signo);
             exit(1);
          }
    }
}
int main() {
    sigset_t oldmask;
    pthread_t tid;
    
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);

    //多线程下设置信号掩码要用这个函数,因为sigprocmask在多线程下可能会出错。
    if (pthread_sigmask(SIG_BLOCK, &mask, &oldmask) != 0)
        exit(100);//出错啦
    pthread_mutex_lock
    //创建用来专门处理信号的子线程
    if (pthread_create(&tid, NULL, thr_fn, 0) != 0)
        exit(101);//出错啦

    pthread_mutex_lock(&lock);
    while (quit_flag == 0)
        pthread_cond_wait(&wait, &lock);
    pthread_mutex_unlock(&lock);

    quit_flag = 0;
    //恢复起始时的进程信号屏蔽字。此时子线程已经退出了,所以现在不是多线程状态了,可以使用sigprocmask了。
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        exit(103);
    exit(0);
}

]]>

本文固定链接: http://zmrlinux.com/2015/07/27/%e7%ba%bf%e7%a8%8b%e5%bc%82%e6%ad%a5%e4%bf%a1%e5%8f%b7/ | Kernel & Me

该日志由 root 于2015年07月27日发表在 Linux kernrl, 进程/线程 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 线程异步信号 | Kernel & Me