这个函数的用法困扰了我很久,虽然有部分原因是apue列子没看明白,但经过一番摸索也加深了我对sigsuspend的理解。
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);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("SIG_BLOCK error");
pr_mask("in critical region: ");
if (sigsuspend(&waitmask) != -1)
err_sys("sigsuspend error");
pr_mask("after return from sigsuspend: ");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("SIG_SETMASK error");
pr_mask("program exit: ");
exit(0);
pr_mask("\nin sig_int: ");
1、关于pause()和sigsuspend()函数,但是不懂他们究竟有些什么区别,在什么时候可以相互替换,什么时候又不可以呢?
简单的说, sigsuspend = unblock + pause
sigsuspend 函数是用于需要先接触 某个信号的阻塞状态 然后等待该信号发生 这样的应用场景; 而使用 pause 在达到这样的效果时肯定是需要先 调用sigprocmask进行取消阻塞,再调用pause去等待,取消阻塞与等待两步之间有时间窗口,在信号发生在调用pause之前任意时刻的话都有可能导致pause之后再也收不到该信号,也就是永远休眠。为了解决这种情况,sigsuspend函数把这两步做成一个原子操作,这就保证不会丢失(错过)信号,也就不会发生永远休眠这种情况(根本不发生该信号时除外)。所以,建议只用sigsuspend去等待信号。
2、
#include "apue.h"
static void sig_int(int);
int
main(void)
{
}
static void
sig_int(int signo)
{
}
=================================================
打印出
program start:
in critical region: SIGINT
^C
in sig_int: SIGINT SIGUSR1
after return from sigsuspend: SIGINT
program exit:
注释1:pr_mask函数是打印当前的信号屏蔽字
如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
解释:
在调用sigsuspend之前只有SIGINT被阻塞,调用sigsuspend后,信号屏蔽字集被临时替换成SIGUSR1,此时可以递送SIGINT,当SIGINT发生,去执行sig_int,注意:在sig_int里会打出in sig_int: SIGINT SIGUSR1 ,是因为操作系统会自动给正在被递送的信号加入屏蔽字集里(apueP250说了正在递送的信号也是未决信号,会被添加到信号屏蔽字中),当sig_int返回,sigsuspend也将返回,此时屏蔽字就是SIGINT。