10

我需要澄清 sigsuspend 主题。我有一个简化的例子

sigset_t mask, oldmask;
sigemptyset (&mask);
sigaddset (&mask, SIGRTMIN+1);
sigprocmask (SIG_BLOCK, &mask, &oldmask);

sigsuspend(&oldmask);

sigprocmask (SIG_UNBLOCK, &mask, NULL);

我是这样理解的:

  • sigemptyset 清除信号列表(掩码) - 因为它是用当前阻塞的信号初始化的(?)
  • sigaddset 将 SIGRTMIN+1 添加到掩码
  • sigprocmask 将 mask+oldmask 中的所有信号设置为阻塞
  • sigsuspend(&oldmask) 暂停线程执行,直到阻塞信号之一到达?如果我想阻止 SIGRTMIN+1,不应该有 sigsuspend(&mask) 吗?

    其次,假设我在一个循环中有这样的 sigsuspend 并且到达了一些 SIGRTMIN+1 信号。对于每个信号,这样的循环会继续吗?在某种队列中?

    while(1){
        sigsuspend(&oldmask)
        printf("recieved signal");
    }
    

    这样对于每个信号我都打印了“接收到的信号”?

  • 4

    1 回答 1

    15

    这个答案的前一版的主要部分是错误的。我为我的错误道歉。我感谢Wotim指出错误。

    POSIX 的定义sigsuspend()

    POSIX 标准sigsuspend()相当清楚地描述:

    #include <signal.h>

    int sigsuspend(const sigset_t *sigmask);

    描述

    sigsuspend()函数应将调用线程的当前信号掩码替换为所指向的信号集,sigmask然后暂停线程,直到传递一个信号,该信号的作用是执行信号捕获函数或终止进程。这不会导致任何其他可能在进程上挂起的信号在线程上变为挂起。

    如果该操作是终止进程,则sigsuspend()永远不会返回。如果该动作是执行信号捕获函数,sigsuspend()则应在信号捕获函数返回后返回,信号掩码恢复为sigsuspend()调用前存在的集合。

    无法阻止无法忽略的信号。这是由系统强制执行的,不会导致指示错误。

    返回值

    由于sigsuspend()无限期暂停线程执行,所以没有成功完成返回值。如果发生返回,则应返回 -1 并设置 errno 以指示错误。

    错误

    如果出现以下情况,该sigsuspend()功能将失败:

    [EINTR] 调用进程捕获信号,并从信号捕获函数返回控制。

    此外,POSIX信号概念说:

    每个线程都有一个“信号掩码”,它定义了当前阻止传递给它的信号集。

    应用到您的代码片段

    sigsuspend()函数是旧pause()函数的现代类似物。

    主要变化:两个代码块颠倒了。

    它允许您将线程发送到睡眠状态,直到其选定的信号之一发生。如果您希望它在 SIGRTMIN+1 到达之前一直休眠,请使用:

    sigfillset(&mask);
    sigdelset(&mask, SIGRTMIN+1);
    sigsuspend(&mask);
    

    这会阻塞除 SIGRTMIN+1 之外的所有信号。

    如果你想睡觉直到 SIGRTMIN+1 以外的信号到达,你使用:

    sigemptyset(&mask);
    sigaddset(&mask, SIGRTMIN+1);
    sigsuspend(&mask);
    

    这仅阻止 SIGRTMIN+1。

    除非您在末尾添加换行符,否则您的循环将无法Received signal可靠打印(甚至可能不会;您可能需要fflush(stdout)或等效)。但是,如果您在正常的事件过程中阻止了 SIGRTMIN+1,然后设置&oldmask为仅允许 SIGRTMIN+1,那么当您的代码位于sigsuspend().

    您的描述sigprocmask()不正确:

    sigprocmask将所有信号设置mask+oldmask为阻塞

    当你这样做时:

    sigset_t mask, oldmask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGRTMIN+1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
    

    您将 SIGRTMIN+1 添加到阻塞信号列表中(因为您使用了 SIG_BLOCK 并且mask仅包含 SIGRTMIN+1)。in 的输出oldmask是添加 SIGRTMIN+1 之前的信号掩码。它可能已经包含也可能不包含 SIGRTMIN+1。pthread_sigprocmask()进程的信号掩码从其当前值更改为包含 SIGRTMIN+1 的新值(如果您需要为线程设置信号掩码,则改为使用),您会被告知旧值。

    从评论中

    sigsuspend(&oldmask)如果我想阻止 SIGRTMIN+1,那么在我的第一个示例中使用是错误的吗?

    重大变化。

    是的,这是错误的。调用sigsuspend(&oldmask)会使您的线程进入睡眠状态,直到oldmask收到其中一个信号。的内容oldmask是在您添加 SIGRTMIN+1 之前被阻止的信号集。

    是的,这是错误的。调用sigsuspend(&oldmask)将您的线程发送到睡眠状态,直到收到输入的信号之一oldmask。的内容oldmask是在您添加 SIGRTMIN+1 之前被阻止的信号集。

    以下两段被撤回,而不是必然被谴责为错误。我认为两者都有真实的元素,尽管两者也有改进的余地。

    您不使用sigsuspend()阻止信号本身;你用它来等待一组指定的信号之一到达。

    如果要忽略SIGRTMIN+1,则需要使用sigaction(),也可以照常使用sigprocmask();专门阻止 SIGRTMIN+1 以及所有其他已被阻止的信号。

    我是否正确理解它会像以前一样阻止相同的信号?

    假设“它”是sigsuspend(),那么它将阻止任何未输入oldmask的信号并等待其中一个信号oldmask到达。

    假设“它”是sigsuspend(),那么它将阻止任何信号进入oldmask并等待其中一个进入的信号oldmask到达。

    如果我这样做sigsuspend(&mask)了,它会阻止 SIGRTMIN+1 和所有信号,oldmask因为sigprocmask(SIG_BLOCK, &mask, &oldmask)

    重大变化

    绝对不!这将暂停线程,直到其中一个信号mask到达。由于唯一的信号mask是 SIGRTMIN+1,只有当它到达时才会sigsuspend()返回。sigprocmask()报告在调用之前被阻止的内容oldmask;它根本没有修改mask(你的变量);它确实通过添加 SIGRTMIN+1 修改了进程的信号掩码。

    绝对不!这将挂起线程,直到输入的信号之一mask到达。由于唯一的信号mask是 SIGRTMIN+1,因此只有该信号被阻塞,当任何其他信号到达时,它将被处理并sigsuspend()返回。sigprocmask()报告在调用之前被阻止的内容oldmask;它根本没有修改mask(你的变量);它确实通过添加 SIGRTMIN+1 修改了进程的信号掩码。


    我强烈建议阅读或重读 POSIX Signal 概念和操纵信号处理的各种函数。(是的,这部分是“医生,治愈你自己”的处方。)

    如果这里还有错误,请告诉我。

    于 2013-03-07T23:55:41.090 回答