背景
我的目标是在一个专用线程上处理某些信号,而不是在信号发出时碰巧在我的进程中运行的任何线程上处理它们。
我这样做如下(在本例中,仅适用于信号16):
在主线程上,在启动任何其他线程之前(错误处理ommited)

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
    }
});

为了取消,我只需要在主线程中设置取消标志。
这个解决方案的问题是,轮询会在响应(取消)和检查取消标志的繁忙工作量之间产生典型的权衡。
2。raise()/sigqueue()/kill()
在这个解决方案中,我在信号掩码中添加了一个专用信号,例如SIGUSR1和以下调用:
sigset_t sigset;
sigaddset(&sigset, 16);
sigaddset(&sigset, SIGUSR1); // <-- added call here
sigprocmask(SIG_BLOCK, &sigset, nullptr);

然后当我需要取消对sigwaitinfo的调用时,我设置了一个cancel标志并调用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会超时?

最佳答案

使用pthread_kill向特定线程发送信号。
例如,代替raise(SIGUSR1);做:

if(int rc = ::pthread_kill(_thread.native_handle(), SIGUSR1))
    // Handle pthread_kill error.

关于c++ - 如何终止对sigwaitinfo的调用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51687753/

10-14 18:42
查看更多