多线程进程中的信号处理

Signal handling in mutlti-threaded process

本文关键字:信号处理 进程 多线程      更新时间:2023-10-16

我有一个在多线程进程中处理信号的基本问题。

在我的代码中,我从主线程创建了一个子线程,以侦听稍后将由主线程触发的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。

您的run_something线程在为该信号调用sigwait之前取消阻止SIGALRM,但这是未定义的行为。sigwait从挂起(即阻塞)信号集合中移除信号。

不要在你的线程中取消阻止,你会看到你期望的行为。

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

因此,在接收信号时,操作系统会按照它应该做的去做,即调用SIGALRM的默认操作,即终止进程。将"闹钟"打印到控制台是默认行为的一部分,BTW.

要解决此问题,请为SIGARLM设置一个信号处理程序。这可以通过使用CCD_ 10以可移植的方式来实现。


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


更新

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

在这种情况下,修复这些问题并不需要设置一个信号处理程序(它仍然可以解决问题,并且是有效的),而是按照pilcorow的回答所建议的那样做,即在调用sigwait()(或sigwaitinfo())之前阻止信号。

此外由于上述原因,请确保使用pthread_sigmask()而不是sigprocmask()


与问题无关

我从主线程创建一个子线程

没有"子"线程这样的概念。创建之后,所有进程的线程都是同一级别上的"兄弟"。这包括使用main()启动的初始线程。"主"线程通常是这样调用的,只是因为它的线程函数的名称:main