【问题标题】:Explanation of sigsuspend needed需要 sigsuspend 的解释
【发布时间】:2013-02-23 09:41:11
【问题描述】:

我需要澄清 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");
    }
    

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

  • 【问题讨论】:

      标签: c unix process signals


      【解决方案1】:

      此答案上一版的主要部分是错误的。我为我的错误道歉。感谢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 Signal concepts 说:

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

      应用到您的代码片段

      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()的描述不正确:

      sigprocmaskmask+oldmask 中的所有信号设置为阻塞

      当你这样做时:

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

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

      来自 cmets

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

      重大变化。

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

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

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

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

      如果你想忽略SIGRTMIN+1,那么你需要使用sigaction()或者你可以像你一样使用sigprocmask();专门阻止 SIGRTMIN+1 以及所有其他已被阻止的信号。

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

      假设“它”是sigsuspend(),那么它将阻塞任何不在oldmask 中的信号,并等待oldmask 中的信号之一到达。

      假设“它”是sigsuspend(),那么它将阻塞oldmask 中的任何信号并等待oldmask 中的not信号之一到达。

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

      重大变化

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

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


      我强烈建议阅读或重新阅读 POSIX Signal concepts 和各种操纵信号处理的函数。 (是的,这在一定程度上是“医生,治愈你自己”的处方。)

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

      【讨论】:

      • 如果我想阻止 SIGRTMIN+1 ,那么在我的第一个示例中使用 sigsuspend(&oldmask) 是错误的吗?我是否正确理解它会像以前一样阻止相同的信号?如果我执行 sigsuspend(&mask) 那么它将阻止 SIGRTMIN+1 和 oldmask 中的所有信号,因为 sigprocmask (SIG_BLOCK, &mask, &oldmask) ??
      • @Jonathan:我认为你混淆了一些东西。 The sigsuspend() function shall replace the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. 这意味着 sigsuspend() 停止挂起如果接收到的信号 not 在 sigmask 中!您在示例中以相反的方式编写了它。
      • @Wotim: POSIX Signal concepts 说:每个线程都有一个“信号掩码”,它定义了当前阻止传递给它的信号集。 因此有一个 MAJOR 问题——反转逻辑——在我的回答中。我会更新的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多