向c++ 11线程传播信号(SIGINT)

Propagating Signal (SIGINT) to C++11 threads

本文关键字:SIGINT 信号 传播 c++ 线程      更新时间:2023-10-16

我试图在接收SIGINT信号(^C)时正确终止我的多线程c++ 11应用程序,但由于某种原因它没有传播到子线程,虽然主线程对它的响应很好。

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

是否有任何方法来修复或解决这种行为?是否有一种方法来传播主接收信号到子线程?

EDIT:用c++ 11 std::this_thread::sleep_for()替换POSIX sleep()

#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 terminationn";
}
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 因此,解决方案是将所有阻塞调用替换为非阻塞调用,以及诸如条件变量和轮询之类的机制。

实际的问题仍然没有答案,因为当前的软件(可能还有硬件)没有设计成在一个线程中处理多个信号的方式,哪个线程应该告诉其他线程在接收信号时做什么。

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

POSIX区分目标处理或线程的信号。无论哪种情况,只有一个线程接收到信号:

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

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

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

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

static int volatile signaled = 0;