多线程编程指南

完成语义

另一种处理信号的方式是使用完成语义。

当信号指明发生灾难性情况,导致没有理由继续执行当前代码块时,请使用完成语义。信号处理程序将代替其余有问题的块运行。换句话说,信号处理程序将完成该块。

在示例 5–3 中,所讨论的块是 if 语句的 then 部分的主体。对 setjmp(3C) 的调用会在 jbuf 中保存程序的当前寄存器状态并返回 0,从而执行块。


示例 5–3 完成语义

sigjmp_buf jbuf;

void mult_divide(void) {

    int a, b, c, d;

    void problem();



    sigset(SIGFPE, problem);

    while (1) {

        if (sigsetjmp(&jbuf) == 0) {

            printf("Three numbers, please:\n");

            scanf("%d %d %d", &a, &b, &c);

            d = a*b/c;

            printf("%d*%d/%d = %d\n", a, b, c, d);

        }

    }

}



void problem(int sig) {

    printf("Couldn't deal with them, try again\n");

    siglongjmp(&jbuf, 1);

}

如果出现 SIGFPE 浮点异常,则系统将调用信号处理程序。

信号处理程序将调用 siglongjmp(3C)(用于恢复 jbuf 中保存的寄存器状态),进而导致程序再次从 sigsetjmp() 返回。保存的寄存器包括程序计数器和栈指针。

但是,此时 sigsetjmp(3C) 将返回 siglongjmp() 的第二个参数(值为 1)。请注意,块将被跳过,而仅在下一次迭代 while 循环期间执行。

可以在多线程程序中使用 sigsetjmp(3C) 和 siglongjmp(3C)。请注意,一个线程永远不会执行使用另一个线程的 sigsetjmp() 结果的 siglongjmp()。

此外,sigsetjmp() 和 siglongjmp() 可以恢复和保存信号掩码,而 setjmp(3C) 和 longjmp(3C) 不会执行这些操作。

使用信号处理程序时,请使用 sigsetjmp() 和 siglongjmp()。

完成语义通常用于处理异常。需要特别指出的是,Sun AdaTM 编程语言就使用此模型。


注 –

请记住,不得将 sigwait(2) 与同步信号一同使用。