将信号(SIGINT)传播到C ++ 11线程

时间:2013-03-27 11:45:13

标签: c++ multithreading c++11 signals

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

对于instnce(如下面的代码示例),如果我们在线程内部有一些阻塞函数(如sleep()),如果您安装了任何SIGNT,它将从您那里取出所有^C控件例如,使用sigaction()函数来挂钩。

有没有办法修复或解决这种行为? 有没有办法将主接收信号传播到子线程?

编辑:用C ++ 11替换POSIX sleep() 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 所以解决方案是用非阻塞对应物替换所有阻塞调用以及诸如条件变量和轮询之类的机制。

实际的问题仍未得到解决,因为当前的软件(可能还有硬件)并不是设计成在一个线程中处理信号的方式,而应该告诉其他人在接收信号时该怎么做。

1 个答案:

答案 0 :(得分:4)

  

我正在尝试在收到SIGINT信号时正确终止我的多线程C ++ 11应用程序(^ C它是),但由于某种原因它不会传播到子线程,尽管主线程很好地响应它。 / p>

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

  

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

     
    

...

  
     

...为该过程生成的信号应该被传递到过程中的那些线程中的一个线程,该线程在调用sigwait()函数时选择该信号或​​者没有阻止信号的传递。如果在调用sigwait()函数时没有线程选择该信号,并且如果进程中的所有线程都阻塞了信号的传递,则该信号将在进程中保持挂起状态,直到线程调用sigwait()函数选择该信号为止。信号,线程解锁信号的传递,或者与信号相关的动作被设置为忽略信号。

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

另外,因为signaled是由信号处理程序设置的,所以它应该被声明为volatile,这是volatile引入的两个用例之一:

static int volatile signaled = 0;