8

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

例如(如下面的代码示例),如果我们在线程内部有一个阻塞函数sleep()(比如^Csigaction()

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

编辑sleep():用 C++11替换 POSIXstd::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 因此,解决方案是用非阻塞对应项以及条件变量和轮询等机制替换所有阻塞调用。

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

4

1 回答 1

4

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

POSIX 区分针对进程或线程的信号。在任何一种情况下,只有一个线程接收到信号:

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

...

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

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

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

static int volatile signaled = 0;
于 2013-03-27T12:06:22.973 回答