需要解释sigsuspend

时间:2013-03-07 23:30:25

标签: c unix process signals

我需要澄清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设置要阻止掩码+旧掩码中的所有信号
  • sigsuspend(& oldmask)暂停线程执行,直到其中一个阻塞信号到达?如果我想阻止SIGRTMIN + 1,是不是应该有sigsuspend(& mask)?

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

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

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

  • 1 个答案:

    答案 0 :(得分:14)

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

      

    每个线程都有一个&#34;信号掩码&#34;它定义了当前阻止传递给它的信号集。

    对代码片段的应用

    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)。 oldmask中的输出是添加SIGRTMIN + 1之前的信号掩码。它可能已经包含SIGRTMIN + 1,也可能没有。进程的信号掩码被更改(如果您需要为线程设置信号掩码,而不是使用pthread_sigprocmask())从其当前值到包含SIGRTMIN + 1的新值,并且你会被告知旧的价值。

    来自评论

      

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

    重大变化。

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

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

    以下两段被撤回而不一定被视为错误。我认为两者都有真实的要素,尽管两者都有改进的余地。

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

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

      

    我是否正确理解它会以同样的方式阻止相同的信号?

    假设&#39;它&#39;是sigsuspend(),然后它会阻止oldmask以外的任何信号并等待oldmask中的一个信号到达。

    假设&#39;它&#39;是sigsuspend(),然后它会阻止oldmask中的任何信号并等待oldmask 之一的信号到达。

      

    如果我sigsuspend(&mask),那么由于oldmask,它会阻止SIGRTMIN + 1和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 concepts以及操纵信号处理的各种函数。 (是的,这部分是处方&#34;医生,治愈你自己&#34;。)

    如果此处仍有错误,请告诉我。