Chinaunix首页 | 论坛 | 博客
  • 博客访问: 993216
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-08 12:16:53

10.16 sigsuspend function

#include

 

int sigsuspend(const sigset_t *sigmask);

 

Returns: 1 with errno set to EINTR

 

这个函数可以允许我们以一个指定的signal maskblock。当指定的信号到来时,suspend返回,signal mask自动还原为sigsuspend调用之前的状况

注意,制定信号的handlersigsuspend返回之前执行。

 

适用场合:

如果我们想执行一段代码,不想让他被SIGINT打断,当我们工作完成后,又想着等待该信号的到来,如果这样做:

(一)不好的做法

(1)sigprocmask先将SIGINT信号给block

(2)做工作

(3)工作完成,将对SIGINTblock打开,用sigprocmask

(4)调用pause()

上面这种方法已经被证明是存在race condition的,因为在(3)(4)之间,甚至在(3)sigprocmask函数返回之前,以及在工作中都有可能接收到这个信号,导致我们在pause()之前,即(3)(4)之间或者(3)sigprocmask返回之前,就执行了该信号的handler。那么我们的pause()将不会再得到信号。根本原因在于(3)(4)之间,打开blockpause()不是原子操作。

这种做法的代码:

sigset_t     newmask, oldmask;

 

      sigemptyset(&newmask);

      sigaddset(&newmask, SIGINT);

 

      /* block SIGINT and save current signal mask */

      if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

          err_sys("SIG_BLOCK error");

 

      /* critical region of code */

 

      /* reset signal mask, which unblocks SIGINT */

      if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

          err_sys("SIG_SETMASK error");

 

      /* window is open */

      pause();  /* wait for signal to occur */

 

      /* continue processing */

 

(二)好的作法

(1)sigprocmask先将SIGINT信号给block

(2)做工作

(3)工作完成, 调用suspend(&newset)来进入block状态,在newset中我们指定SIGINT不被block

这样(3)中SIGINTunblock操作和等待成了一个原子操作。我们不再丢失SIGINT

这种做法的代码:

Figure 10.22. Protecting a critical region from a signal

#include "apue.h"

 

static void sig_int(int);

 

int

main(void)

{

    sigset_t    newmask, oldmask, waitmask;

 

    pr_mask("program start: ");

 

    if (signal(SIGINT, sig_int) == SIG_ERR)

        err_sys("signal(SIGINT) error");

    sigemptyset(&waitmask);

    sigaddset(&waitmask, SIGUSR1);

    sigemptyset(&newmask);

    sigaddset(&newmask, SIGINT);

 

    /*

     * Block SIGINT and save current signal mask.

     */

    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

        err_sys("SIG_BLOCK error");

 

    /*

     * Critical region of code.

     */

    pr_mask("in critical region: ");

 

    /*

     * Pause, allowing all signals except SIGUSR1.

     */

    if (sigsuspend(&waitmask) != -1)

        err_sys("sigsuspend error");

 

    pr_mask("after return from sigsuspend: ");

 

    /*

     * Reset signal mask which unblocks SIGINT.

     */

    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

        err_sys("SIG_SETMASK error");

 

    /*

     * And continue processing ...

     */

    pr_mask("program exit: ");

 

    exit(0);

}

 

static void

sig_int(int signo)

{

    pr_mask("\nin sig_int: ");

}

执行结果:

$ ./a.out

   program start:

   in critical region: SIGINT

 

   ^?                               type the interrupt character

   in sig_int: SIGINT SIGUSR1

   after return from sigsuspend: SIGINT

   program exit

 

还有一个例子,这个例子等待SIGINTSIGQUIT信号,但只有SIGQUIT信号使程序退出。:

Figure 10.23. Using sigsuspend to wait for a global variable to be set

#include "apue.h"

 

volatile sig_atomic_t    quitflag;    /* set nonzero by signal handler */

 

static void

sig_int(int signo)  /* one signal handler for SIGINT and SIGQUIT */

{

    if (signo == SIGINT)

        printf("\ninterrupt\n");

    else if (signo == SIGQUIT)

        quitflag = 1;   /* set flag for main loop */

}

 

int

main(void)

{

     sigset_t     newmask, oldmask, zeromask;

 

     if (signal(SIGINT, sig_int) == SIG_ERR)

         err_sys("signal(SIGINT) error");

     if (signal(SIGQUIT, sig_int) == SIG_ERR)

         err_sys("signal(SIGQUIT) error");

 

     sigemptyset(&zeromask);

     sigemptyset(&newmask);

     sigaddset(&newmask, SIGQUIT);

 

     /*

      * Block SIGQUIT and save current signal mask.

      */

     if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

         err_sys("SIG_BLOCK error");

 

     while (quitflag == 0)

         sigsuspend(&zeromask);

 

     /*

      * SIGQUIT has been caught and is now blocked; do whatever.

      */

     quitflag = 0;

 

     /*

      * Reset signal mask which unblocks SIGQUIT.

      */

     if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

         err_sys("SIG_SETMASK error");

 

     exit(0);

}

结果:

$ ./a.out

 

   ^?                type the interrupt character

   interrupt

 

   ^?                type the interrupt character again

   interrupt

 

   ^?                and again

   interrupt

 

   ^?                and again

   interrupt

 

   ^?                and again

   interrupt

 

   ^?                and again

   interrupt

 

   ^?                and again

   interrupt

 

   ^\ $              now terminate with quit character

阅读(555) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~