多线程过程中的信号处理

时间:2016-07-21 14:41:15

标签: c++ multithreading signals

我遇到了在多线程过程中处理信号的基本问题。

在我的代码中,我从主线程创建一个子线程,以收听SIGALRM稍后将被主线程触发(使用其他函数,如timer_create给我相同的结果所以请不要专注于此。)

问题是,整个过程终止于控制台上的一个奇怪的“闹钟”输出,而不是捕捉到信号。

这是我的代码:

#include <iostream>
#include <sys/time.h>
#include <unistd.h>
#include <csignal>

using namespace std;

void* run_something(void* args){
    //unblock the SIGALRM to be catched
    sigset_t sig;
    sigemptyset(&sig);
    sigaddset(&sig, SIGALRM);
    sigprocmask(SIG_UNBLOCK, &sig, NULL); //tried with pthread_sigmask

    //wait for SIGALRM
    int catchedSig;
    sigwait(&sig, &catchedSig);
    cout<<"in sub-thread, SIGALRM catched, return"<<endl;
}

int main(int argc, char** argv){
    //block SIGALRM in main thread
    sigset_t sig;
    sigemptyset(&sig);
    sigaddset(&sig, SIGALRM);
    sigprocmask(SIG_BLOCK, &sig, NULL);

    //create new thread
    pthread_t thread;
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_create(&thread, &attr, run_something, NULL);

    //trigger SIGARLM after 2s
    alarm(2); //tried with timer_create/sigevent

    //wait
    cout<<"in main thread, waiting for sub-thread to terminate"<<endl;
    pthread_join(thread, NULL);
    cout<<"in main thread, terminating"<<endl;

    return EXIT_SUCCESS;
}

预期结果

  • 在主线程中,等待子线程终止
  • 在子线程中,SIGALRM被抓住,返回
  • 在主线程中,终止

观察结果

  • 在主线程中,等待子线程终止
  • 闹钟

其他信息: 我正在使用g ++(Debian 5.4.0-4)5.4.0 20160609。

2 个答案:

答案 0 :(得分:2)

您的run_something线程在致电sigwait之前取消阻止SIGALRM,但this is undefined behaviorsigwait从待处理(即阻止)信号集中删除信号。

请勿在您的帖子中取消阻止,并且您会看到您期望的行为。

答案 1 :(得分:1)

显示的代码没有为SIGARLM设置任何信号处理程序。

因此,在信号接收时,操作系统应该按照它应该调用SIGALRM's default action,即终止进程。将“闹钟”打印到控制台是默认行为BTW。

的一部分

要解决此问题,请设置SIGARLM的信号处理程序。这可以通过sigaction()以便携式方式完成。

也不要在多线程程序中使用sigprocmask(),因为它的行为未指定。请改用pthread_sigmask()

<强>更新

我错过了代码调用sigwait() ...:}

在这种情况下解决这个问题并不需要设置一个信号处理程序(它仍然可以解决问题并且是有效的)但是按照pilcrowanswer的建议行事,即在调用sigwait()(或sigwaitinfo())之前阻止信号。

此外请确保使用pthread_sigmask()代替sigprocmask(),原因如下。

与问题无关

  

我从主线程

创建一个子线程

没有“sub”-threads这样的概念。在创建之后,所有进程'线程都是“兄弟姐妹”在同一级别上。这包括使用main()开始的初始线程。 “main”-thread通常以这种方式调用,因为它的线程函数的名称:main