如何使用sigsuspend

时间:2013-04-16 16:01:37

标签: c

我有这个代码,我必须重复等待信号程序块。我的老师希望我们使用sigsuspend和面具而不是暂停或睡眠。我不熟悉sigsuspend或mask,我知道sigsuspend()暂时用掩码给出的掩码替换调用进程的信号掩码,然后暂停进程直到传递一个信号,其动作是调用信号处理程序或终止进程。 但是我该如何实现呢。

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

unsigned Conta = 0;

void mypause(int sign)
{
    switch (sign)
    {
        case SIGINT:
            printf("You've pressed ctrl-C\n");
            printf("I'm running waiting for a signal...\n");
            Conta++;
            break;

        case SIGQUIT:
            printf("You've pressd ctrl-\\n");
            printf("Number of times you've pressed CTRL-C: %d", Conta); 
            exit(0);
            break;
    }
}

int main()
{
    alarm(3);
    printf("I'm Alive\n");

    signal(SIGINT, mypause);
    signal(SIGQUIT, mypause);
    printf("I'm running, waiting for a signal...\n");
    while (1)
    {
    }

    return (0);
}

3 个答案:

答案 0 :(得分:8)

简单的入门方法是只用空掩码调用sigsuspend(即任何信号都可以唤醒程序):

sigset_t myset;
(void) sigemptyset(&myset);
while (1) {
    (void) printf("I'm running, waiting for a signal...\n");
    (void) sigsuspend(&myset);
}

下一步是使用sigprocmask来禁用两个处理过的信号(SIGINTSIGQUIT),而不是在{{1}中等待它们时}。然后你会使用从sigsuspend获得的“旧面具”,而不是悬挂时的空面具。

答案 1 :(得分:7)

GNU libc manual说明似乎清晰透彻:

  

功能:int sigsuspend(const sigset_t * set)

     

此函数用set替换进程的信号掩码,然后暂停   处理直到传递其行动的信号   要么终止进程,要么调用信号处理功能。   换句话说,该程序有效地暂停,直到其中一个   不属于集合成员的信号到达。

     

如果通过传递调用处理函数的信号唤醒进程,   并且处理函数返回,然后是sigsuspend   也回来了。

     

只要sigsuspend正在等待,掩码就会保持设置状态。功能sigsuspend   总是恢复以前的信号掩码   回报。

     

返回值和错误条件与暂停相同。

     

使用sigsuspend,您可以替换中的暂停或睡眠循环   上一节完全可靠:

 sigset_t mask, oldmask;

 ...

 /* Set up the mask of signals to temporarily block. */
 sigemptyset (&mask);
 sigaddset (&mask, SIGUSR1);

 ...

 /* Wait for a signal to arrive. */
 sigprocmask (SIG_BLOCK, &mask, &oldmask);
 while (!usr_interrupt)
   sigsuspend (&oldmask);
 sigprocmask (SIG_UNBLOCK, &mask, NULL);
     

这最后一段代码有点棘手。要记住的关键点   这是当sigsuspend返回时,它会重置进程的信号   掩码到原始值,从调用之前的值   sigsuspend-在这种情况下,SIGUSR1信号再次被阻止。该   第二次调用sigprocmask是显式取消阻止它的必要条件   信号。

     

另一点:您可能想知道为什么while循环是必要的   因为该程序显然只等待一个SIGUSR1   信号。答案是传递给sigsuspend的掩码允许   通过传递其他类型的信号唤醒的过程,如   好的,例如,工作控制信号。如果这个过程被a唤醒了   没有设置usr_interrupt的信号,它只是暂停自己   直到“正确”的信号最终到来。

     

这项技术需要更多的准备工作,但事实如此   对于您想要使用的每种等待标准,只需要一次。该   实际等待的代码只有四行。

答案 2 :(得分:1)

-通过使用 sigsuspend() API,一个进程可以暂停它的执行,直到任何一个 信号是从一组信号中传递出来的。

  • 等待信号的干净可靠的方法是阻塞它并 然后使用 sigsuspend。

  • 通过在循环中使用 sigsuspend,可以等待某种 信号同时允许其他类型的信号由它们处理 处理程序。

  • 它允许进程暂停执行,直到收到一个 mask指向的集合中不存在的信号。

  • 语法:int sigsuspend(sigset_t *mask);

  • 它用一个新的掩码临时替换当前的掩码并 一旦信号处理程序返回,就会恢复。

  • 由于 sigsuspend() 无限期地暂停线程执行,所以有 没有成功完成返回值,失败返回-1。

这个程序确保 SIGKILL 和 SIGTERM 程序在临界区执行时信号被阻塞 并在发出 SIGINT 信号后恢复执行 执行相应的信号处理程序 */

     #include <stdio.h>
     #include <string.h>
     #include <errno.h>
     #include <signal.h>


     int cs = 0;
     int value = 5;

     /* This is the function called on receipt of signal(cntl+c) */
     void sig_handler (int sig)
     {
        printf("\n This is signal handler for signal %d\n", sig);
        cs =1;
     }

    int main()
    {
        struct sigaction act;
        act.sa_handler = sig_handler;
        sigemptyset (&act.sa_mask);
        sigaddset (&act.sa_mask, SIGPIPE);
        act.sa_flags = 0;

        sigset_t sig_term_kill_mask;
        sigaddset (&sig_term_kill_mask, SIGTERM);
        sigaddset (&sig_term_kill_mask, SIGKILL);

        sigaction (SIGINT, &act, NULL);

        /* Critical section */
        value++;
        printf ("\n Value is %d\n", value);
        while (cs == 0)
            sigsuspend (&sig_term_kill_mask);

        printf("\n Return from suspended successful\n");
        int ret = sigismember (&act.sa_mask, SIGPIPE);
        if (ret)
            printf("\n Old Mask that is SIGPIPE is restored after return from sigsuspend\n");
        else
            printf("\n Old Mask that is SIGPIPE failed to restored after return from sigsuspend\n");

         return 0; }

输出:

gcc sigsuspend.c

./a.out

值为 6 ^C 这是信号 2 的信号处理程序

暂停成功返回

从 sigsuspend 返回后恢复为 SIGPIPE 的旧 Mask