免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2467 | 回复: 2
打印 上一主题 下一主题

关于sigsuspend的原子操作 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-13 00:18 |只看该作者 |倒序浏览
在apue1中的代码是这样:
int main(void) {
   sigset_t   newmask, oldmask, zeromask;

   if (signal(SIGINT, sig_int) == SIG_ERR)
      err_sys("signal(SIGINT) error");

   sigemptyset(&zeromask);

   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: ");

   /* allow all signals and pause */
   if (sigsuspend(&zeromask) != -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 ... */
   exit(0);
}

static void sig_int(int signo) {
   pr_mask("\nin sig_int: ");
   return;
}

结果:
$a.out
in critical region: SIGINT
^C
in sig_int: SIGINT
after return from sigsuspend: SIGINT

对在in critical region后所出现SIGINT 的解释是这样的:
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。

而当我看apue2的代码的时候,感觉如果按照上面的原子操作就有点问题,请高手指点下:

下面是apue2的代码

#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:

若按照上面那个sigsuspend的理解:
(1) 设置新的mask阻塞当前进程;
    那么此时的mask为waitmask

(2) 收到信号,恢复原先mask;
    收到信号SIGINT, 先恢复mask--->此时的mask就为 newmask与oldmask并集的那个mask鸟 ( sigprocmask(SIG_BLOCK, &newmask, &oldmask)  )
      而在此mask中SIGUSR1并没阻塞
(3) 调用该进程设置的信号处理函数;
    调用sig_int函数--->此时的mask已经还原,所以只有SIGINT,不会出现SIGUSR1. 但是程序的结果是in sig_int: SIGINT SIGUSR1. 我想不通为什么会出现SIGUSR1

(4) 待信号处理函数返回后,sigsuspend返回。

论坛徽章:
0
2 [报告]
发表于 2007-08-13 20:19 |只看该作者
自己顶~~~~

论坛徽章:
0
3 [报告]
发表于 2007-10-28 19:03 |只看该作者
源程序没有错。

sigsuspend 函数一执行,
第一:设置当前进程的信号阻塞为waitmask,也就是SIGUSR1
第二:进入pause 状态

这两步是原子动作。

接着进程收到来在键盘的crtl+c 也就是SIGINT 信号,注意:这个时候进程进入sig_int 函数去处理SIGINT信号,与此同时将SIGINT信号写入当前进程所阻塞的信号列表之中!!(这是关键!)

所以在接下来的输出中会同时显示 SIGUSR1 和 SIGINT

如果不信你自己可以定义其它信号:

我做了实验,源代码如下:

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

static void sig_int(int);
static void sig_chld(int);
static void pr_mask(char *a);

int main()
{
    sigset_t newmask,oldmask,waitmask;

    pr_mask("\nprogram start:");

    if(signal(SIGINT,sig_int)==SIG_ERR)
       {
           printf("\nError in sinal!\n");
           return 1;
       }

    if(signal(SIGCHLD,sig_chld)==SIG_ERR)
       {
           printf("\nError in sinal!\n");
           return 1;
       }


    sigemptyset(&waitmask);
    sigaddset(&waitmask,SIGUSR1);
    sigemptyset(&newmask);
    sigaddset(&newmask,SIGCHLD);
    sigaddset(&newmask,SIGQUIT);
    sigaddset(&newmask,SIGINT);

    if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)
       {
           printf("\nError in sigprocmask!\n");
           return 1;
       }
    pr_mask("\nin critical region:");

    if(sigsuspend(&waitmask)!=-1)
       {
           printf("\nError in sigsuspend!\n");
           return 1;
       }

    pr_mask("\nafter return from sigsuspend:");

    if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)
       {
           printf("\nError in sigprocmask!\n");
           return 1;
       }

    pr_mask("\nprogram exit:");

    return 0;
}

static void sig_chld(int signo)
{
    pr_mask("\nin sig_chld:");
}

static void sig_int(int signo)
{
    pr_mask("\nin sig_int:");
}

static void pr_mask(char *a)
{
        sigset_t   sigset;
        int        errno_save;

        errno_save = errno;
        if (sigprocmask(0, NULL, &sigset) < 0)
           {
               printf("\nError in pr_mask sigprocmask!\n");
               exit (1);
            }

        printf("%s", a);
        if (sigismember(&sigset, SIGINT))        printf("SIGINT ");
        if (sigismember(&sigset, SIGQUIT))        printf("SIGQUIT ");
        if (sigismember(&sigset, SIGUSR1))        printf("SIGUSR1 ");
        if (sigismember(&sigset, SIGALRM))        printf("SIGALRM ");
        if (sigismember(&sigset, SIGCHLD))        printf("SIGCHLD ");
        printf("\n");
        errno = errno_save;
}



在一个窗口执行程序:

$ gcc ./sigsuspend.c -o ./sigsuspend
$ ./sigsuspend

program start:

in critical region:SIGINT SIGQUIT SIGCHLD



此时这个窗口中程序处于pause状态,在另外一个窗口查处此进程的ID,然后kill -CHLD ***  发送SIGCHLD 信号给进程

bsd#
bsd# kill -CHLD 16549
bsd#


然后查看第一个窗口,此时程序执行完毕,输出如下:

$ gcc ./sigsuspend.c -o ./sigsuspend
$ ./sigsuspend

program start:

in critical region:SIGINT SIGQUIT SIGCHLD

in sig_chld:SIGUSR1 SIGCHLD

after return from sigsuspend:SIGINT SIGQUIT SIGCHLD

program exit:
$



果然:  in sig_chld:SIGUSR1 SIGCHLD    中包含了  SIGCHLD  信号!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP