【问题标题】:Child thread raising a signal it is ignoring子线程引发它忽略的信号
【发布时间】:2017-11-15 04:38:17
【问题描述】:

在错误情况下,我想允许子线程发出信号,然后被父线程捕获。然后另一个线程安全地终止整个进程。我看到的问题是,如果我在创建过程中阻止子线程使用 pthread_sigmask 接收信号,那么其他线程看不到它发出的信号。这是预期的行为吗?我该怎么办?

我检查了here 和许多其他类似的,但它们处理来自进程外部的信号。

示例代码如下,请原谅在信号处理程序中使用不允许的函数,因为它有助于示例。我在这里使用了 SIGABRT,因为它有一个非常明显的默认处理程序,但是如果使用 SIGUSR1,行为是相同的。

#include <unistd.h>
#include <signal.h>
#include <iostream>
#include <thread>

void sigHandler(int )
{
  std::cout << "Caught signal in " << std::this_thread::get_id() << std::endl;
}

void threadMain()
{
  std::cout << "Child is " << std::this_thread::get_id() << std::endl;
  sleep(1);
  raise(SIGABRT);
  std::cout << "Child exiting" << std::endl;
}

int main(int argc, char** argv)
{
  std::cout << "Parent is " << std::this_thread::get_id() << std::endl;
  struct sigaction psa;
  psa.sa_handler = sigHandler;
  sigaction(SIGABRT, &psa, nullptr);
  sigset_t set;
  sigemptyset(&set);
  sigaddset(&set, SIGABRT);
  if (argc > 1)
  {
    if (pthread_sigmask(SIG_BLOCK, &set, NULL) == 0)
      std::cout << "Masking complete" << std::endl;
    else
      std::cout << "Failed to mask" << std::endl;
  }
  std::thread child(threadMain);
  if (argc > 1)
  {
    if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) == 0)
      std::cout << "Unmask complete" << std::endl;
    else
      std::cout << "Failed to mask" << std::endl;
  }
  sleep(2);
  child.join();
}

如果你用

编译
g++ --std=c++11 -lpthread main.cpp -g -o main

并使用./main 运行,输出为:

Parent is 140042782496544
Child is 140042766427904
Caught signal in 140042766427904
Child exiting

所以信号被捕获,但被孩子(不是父母,就像我想要的那样)。如果你用./main 1 运行它,输出是:

Parent is 140070068569888
Masking complete
Unmask complete
Child is 140070052501248
Child exiting

即信号被屏蔽了,所以孩子看不到它(这是我想要的),但父母也没有看到它。

我怎样才能确保信号是由孩子提出并由父母照料的?

【问题讨论】:

  • 为什么不使用 C++ 异常?

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


【解决方案1】:

manual for raise(3) 似乎表明它专门将信号发送给调用线程,而不是整个进程,因此一个线程发出的信号不会被另一个线程看到:

raise() 函数向调用进程或线程发送一个信号。在单线程程序中相当于

      kill(getpid(), sig);

在多线程程序中相当于

      pthread_kill(pthread_self(), sig);

raise(SIGABRT) 显式更改为kill(getpid(), SIGABRT) 似乎可以做你想做的事,并将信号发送到整个进程,因此它被一些没有阻塞的线程捕获。

【讨论】:

  • 正好解决了,使用kill是一个很好的解决方案。谢谢!
【解决方案2】:

在我看来,您希望 raise() 进行线程通信 - 嗯,它没有。所以你想做的事情是不可能直接做的。

但是,您可以设置一个变量,或使用您的处理程序中的任何其他线程通信来向您的主线程报告信号已引发。

或者,您可以使用 pthread_kill...

【讨论】:

    猜你喜欢
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 2023-03-16
    • 1970-01-01
    • 2021-03-11
    相关资源
    最近更新 更多