当信号指明发生灾难性情况,导致没有理由继续执行当前代码块时,请使用完成语义。信号处理程序将代替其余有问题的块运行。换句话说,信号处理程序将完成该块。
在示例 5–3 中,所讨论的块是 if 语句的 then 部分的主体。对 setjmp(3C) 的调用会在 jbuf 中保存程序的当前寄存器状态并返回 0,从而执行块。
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 编程语言就使用此模型。