2013-03-27 44 views
6

我试图在接收到SIGINT信号(^C)时正确终止我的多线程C++ 11应用程序,但由于某些原因,它不会传播到子线程,尽管主线程很好地回应了它。向C++ 11线程传播信号(SIGINT)

对于instnce(如下面的代码样本中),如果我们有螺纹(类似sleep())内部的一些阻塞函数,它会拿出从你所有^C控制,如果你使用,比如安装在任何SIGNT挂钩,sigaction()功能。

有什么方法可以解决或解决此类问题? 有没有办法将主要接收的信号传播给子线程?

EDIT:取代POSIX sleep()与C++ 11 std::this_thread::sleep_for()

#include <iostream> 
#include <thread> 
#include <chrono> 
#include <signal.h> // for sigaction() function 

static int signaled = 0; 

void threaded_foo() { 
    while (!signaled) { 
    // pressing ^C now will not lead to correct termination, because we are 
    // sleeping for a long time (100500 seconds) and do not respond to 
    // SIGINT for some tricky reason i am looking a bypassage for. 
    std::chrono::seconds duration(100500); 
    std::this_thread::sleep_for(duration); 
    } 
    std::cout << "Correct termination\n"; 
} 

void sighandler(int sig, siginfo_t *siginfo, void *context) { 
    signaled = 1; 
} 

void install_sig_hooks() { 
    struct sigaction action; 
    memset(&action, 0, sizeof(struct sigaction)); 
    action.sa_sigaction = sighandler; 
    action.sa_flags  = SA_SIGINFO; 
    sigaction(SIGINT, &action, NULL); 
} 

int main(int argc, char **argv) { 
    install_sig_hooks(); 

    std::thread t(threaded_foo); 
    t.join(); 
    return 0; 
} 

EDIT2 所以该溶液来代替与非阻断-同行等机制,条件变量和轮询所有阻塞调用。

实际的问题仍然没有得到解答,因为目前的软件(也可能是硬件)并非设计成在一个线程中处理信号,而是在一个线程中处理信号,这个线程应该告诉别人接收信号时该做些什么。

+0

你为什么混合POSIX'sleep'功能用C++ 11线程? – 2013-03-27 11:47:30

+0

只是为了举例,在实际应用中它是ZeroMQ send()函数,具有完全相同的效果。 – 2013-03-27 11:48:08

+0

好吧,的确,这是一个糟糕的例子,我肩负着使用'std :: this_thread :: sleep_for()'来代替。对不起,让我纠正我的例子。 – 2013-03-27 11:51:53

回答

4

我想在收到SIGINT信号(^ C是)正确地终止我的多线程C++ 11的应用程序,但由于某些原因,它不传播到子线程,但主线程对其作出响应好。

POSIX distinguishes signals targeted to process or a thread。在任一种情况下,只有一个线程接收到信号:

在生成时,应确定是否为进程或进程内的特定线程生成了信号。应该为引起信号产生的线程产生由可归因于特定线程的某些动作产生的信号,例如硬件故障。应为过程生成与进程ID或进程组ID或异步事件(如终端活动)关联生成的信号。

...

...的过程中产生的信号将被输送至处理这是在一个呼叫到一个调用sigwait()函数中的那些线程的选择该信号正好一个或没有阻止信号的传递。如果在调用sigwait()函数时没有线程选择该信号,并且进程中的所有线程都阻止了信号的传递,则信号应该在进程上保持挂起状态,直到线程调用sigwait()函数,选择该函数信号,线程解除信号的传送,或者与信号相关的动作被设置为忽略信号。

在一个多线程的过程中,一个常见的解决方案是阻止一个有意在所有线程中处理的进程信号。这一个线程通常会处理所有的进程信号,并告诉其他线程应该做什么(例如终止)。

而且,因为signaled是由信号处理程序设置,它应该被宣布为volatile,这是引入的两个用例volatile之一:

static int volatile signaled = 0; 
+0

您的答案出现了两个新问题:1)如何中断C++ 11中的线程,所有sleep()都会唤醒?和2)你如何实际终止C++ 11清单的线程? – 2013-03-27 12:10:57

+0

感谢不稳定的通知,但只是为了记录,相同的代码正常工作与理智的睡眠持续时间值,如一秒钟。尽管这种行为可能没有明确定义。 – 2013-03-27 12:15:19

+1

@AlexanderTumin我建议反对线程中断,因为您可能使用的第三方库可能无法正确处理中断。有礼貌地告诉你的线索终止,然后等待。这假定你的所有线程都有某种事件循环,这样他们可以被告知终止。 – 2013-03-27 12:15:31