需要解释sigsuspend

xwh*_*hyz 10 c unix signals process

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

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

sigsuspend(&oldmask);

sigprocmask (SIG_UNBLOCK, &mask, NULL);
Run Code Online (Sandbox Code Playgroud)

以下是我对此的理解:

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

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

    while(1){
        sigsuspend(&oldmask)
        printf("recieved signal");
    }
    
    Run Code Online (Sandbox Code Playgroud)

    这样,对于每个信号,我都会收到"收到的信号"吗?

  • Jon*_*ler 15

    上一版本答案的主要部分是错误的.我为我的错误道歉.我感谢Wotim指出错误.

    POSIX的定义 sigsuspend()

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

    #include <signal.h>

    int sigsuspend(const sigset_t *sigmask);

    描述

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

    如果行动是终止过程,则sigsuspend()永远不会返回.如果动作是执行信号捕获功能,sigsuspend()则应在信号捕获功能返回后返回,信号掩码恢复到sigsuspend()呼叫前存在的设置.

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

    返回值

    由于sigsuspend()无限期挂起线程执行,因此没有成功的完成返回值.如果发生返回,则返回-1并设置errno以指示错误.

    错误

    sigsuspend()IF函数将失败:

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

    此外,POSIX Signal概念说:

    每个线程都有一个"信号掩码",用于定义当前阻止传递给它的信号集.

    应用于您的代码片段

    sigsuspend()功能是旧pause()功能的现代模拟.

    主要变化:两个代码块反转.

    它允许您将线程发送到睡眠状态,直到其中一个选定信号出现.如果你希望它在SIGRTMIN + 1到达之前休眠,你可以使用:

    sigfillset(&mask);
    sigdelset(&mask, SIGRTMIN+1);
    sigsuspend(&mask);
    
    Run Code Online (Sandbox Code Playgroud)

    这会阻止除SIGRTMIN + 1之外的所有信号.

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

    sigemptyset(&mask);
    sigaddset(&mask, SIGRTMIN+1);
    sigsuspend(&mask);
    
    Run Code Online (Sandbox Code Playgroud)

    这仅阻止SIGRTMIN + 1.

    Received signal除非你在最后添加换行符,否则你的循环将无法可靠地打印(也许甚至不是;你可能需要fflush(stdout)或等效).但是,如果在正常的事件过程中阻塞了&oldmaskSIGRTMIN + 1,然后设置为仅允许SIGRTMIN + 1,则在代码进入时可以可靠地传递信号sigsuspend().

    您的描述sigprocmask()不正确:

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

    当你这样做时:

    sigset_t mask, oldmask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGRTMIN+1);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);
    
    Run Code Online (Sandbox Code Playgroud)

    您将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概念和操作信号处理的各种功能.(是的,这部分是"医生,治愈你自己"的处方.)

    如果这里仍有错误,请告诉我.