线程异步信号

先容我吐槽一下《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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值