首页 文章

需要解释sigsuspend

提问于
浏览
9

我需要澄清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设置要阻止掩码oldmask中的所有信号

  • sigsuspend(&oldmask)挂起线程执行,直到其中一个被阻塞的信号到达?如果我想阻止SIGRTMIN 1,是不是应该有sigsuspend(&mask)?

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

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

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

1 回答

  • 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说:

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

    应用于您的代码片段

    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设置要阻止掩码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.进程's signal mask is changed (if you needed to set the signal mask for a thread, you' d使用 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以及已被阻止的所有其他信号 .

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

    假设'它'是sigsuspend(),那么它将阻止任何不在oldmask中的信号并等待oldmask中的一个信号到达 .

    假设'it'是 sigsuspend() ,那么它将阻止 oldmask 中的任何信号并等待 oldmask 中的一个信号到达 .

    如果我执行sigsuspend(&mask),那么由于sigprocmask(SIG_BLOCK,&mask和oldmask),它会阻止SIGRTMIN 1和oldmask中的所有信号?

    重大变化

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

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


    我强烈建议阅读或重读POSIX Signal concepts以及操纵信号处理的各种功能 . (是的,这部分是"Physician, heal thyself"的处方 . )

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

相关问题