在错误情况下,我想允许子线程引发一个信号,然后由父线程捕获。然后另一个线程安全地终止整个过程。我看到的问题是,如果我阻止子线程在创建过程中使用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
即。信号被阻止,所以孩子没有看到它(这是我想要的),但父母也没有看到它。
如何确保信号由孩子提出并由父母提出?
答案 0 :(得分:2)
manual for raise(3)
似乎表示它将信号专门发送给调用线程,而不是整个进程,因此另一个线程不会看到由一个线程引发的信号:
raise()
函数向调用进程或线程发送信号。在单线程程序中,它等同于kill(getpid(), sig);
在多线程程序中,它等同于
pthread_kill(pthread_self(), sig);
明确地将raise(SIGABRT)
更改为kill(getpid(), SIGABRT)
似乎可以执行您想要的操作,并将信号发送到整个进程,因此它会被某个没有被阻止的线程捕获。
答案 1 :(得分:1)
听起来像你想让raise()进行线程通信 - 嗯,它没有。所以你想做的事情是不可能的。
但是,您可以设置变量,或使用处理程序中的任何其他线程通信向主线程报告信号已被引发。
或者,您可以使用pthread_kill ...