我的目标是在专用线程上处理某些信号,而不是在信号发出时在我的进程中正在运行的任何线程上处理它们。
我正在执行以下操作(在此示例中,仅适用于信号16):
在主线程上,在启动任何其他线程之前(忽略错误处理)
sigset_t sigset;
sigaddset(&sigset, 16);
sigprocmask(SIG_BLOCK, &sigset, nullptr);
然后,我创建一个线程来等待这些信号(在此示例中仅为16):
std::thread _thread = std::thread([&]()
{
int ret = sigwaitinfo(&sigset, nullptr);
if (ret == 16)
{
// handle signal 16
}
});
这很好。
但是,我希望能够在需要时取消对sigwaitinfo的调用。
我尝试了两种解决方案,但都不足够:
(有效的)一个选项不是使用sigwaitinfo,而是使用sigtimedwait,它接受超时参数。 这使我可以使用轮询,并在下次通话返回并设置一些取消标志时取消。 线程中的代码如下:
std::atomic<bool> _cancel (false);
std::thread _thread = std::thread([&]()
{
timespec _timespec {0, 1}; // 1 second
int ret = sigtimedwait(&sigset, nullptr, _timespec);
if (_cancel)
{
return;
}
if (ret == 16)
{
// handle signal 16
}
});
为了取消,我只需要在主线程中设置_cancel标志。 这种解决方案的问题在于,轮询会导致(取消)响应性和检查取消标志所完成的工作量之间的典型权衡。
在此解决方案中,我通过以下调用将专用信号添加到信号掩码,例如SIGUSR1:
sigset_t sigset;
sigaddset(&sigset, 16);
sigaddset(&sigset, SIGUSR1); // <-- added call here
sigprocmask(SIG_BLOCK, &sigset, nullptr);
然后,当我需要取消对sigwaitinfo的调用时,我设置了一个取消标志并调用raise(SIGUSR1)
线程中的代码如下:
std::atomic<bool> _cancel (false);
std::thread _thread = std::thread([&]()
{
int ret = sigwaitinfo(&sigset, nullptr);
if (_cancel) // <-- now check _cancel flag before handling signal
{
return;
}
if (ret == 16)
{
// handle signal 16
}
});
取消操作如下:
_cancel = true; // <-- set the flag before raising the signal
raise(SIGUSR1);
此解决方案的问题是它不起作用,因为对raise()的调用不会导致sigwaitinfo在专用线程中返回。我相信根据文档,它只会在执行线程本身中发出信号。 sigqueue()和kill()也不起作用。
有没有一种方法可以使sigwaitinfo过早返回,而无需循环调用sigtimedwait并超时?
答案 0 :(得分:0)
使用pthread_kill
将信号发送到特定线程。
例如,代替raise(SIGUSR1);
:
if(int rc = ::pthread_kill(_thread.native_handle(), SIGUSR1))
// Handle pthread_kill error.
答案 1 :(得分:0)
这是我找到的解决方案。
我已验证此解决方案是可靠的。
可以在以下文档中找到更多详细信息:
signalfd
,eventfd
和poll