分类: C/C++
2012-07-26 08:31:32
先来看看函数原型:
点击(此处)折叠或打开
函数sigsuspend将进程的信号屏蔽码设置为mask,然后与pause()函数一样等待信号的发生并执行完信号处理函数。信号处理函数执行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigsuspend函数才返回。 Sigsuspend总是返回-1。 --------《LinuxC编程实战》
将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。
注意,此函数没有成功返回值。如果它返回到调用者则总是返回-1,并将errno设置为EINTR(表示为一个被中断的系统调用)。 ------ 《UNIX环境高级编程》第二版
sigsuspend是一个原子操作
(1)设置新的mask阻塞当前进程
(2)收到信号,恢复原先mask
(3)调用该进程设置的信号处理函数
(4)待信号处理函数返回后,sigsuspend返回
理解:suspend的功能就是将进程当前的屏蔽信号码设置为指定的信号set,让进程挂起,再等待一次非屏蔽的信号,接受到信号后,将信号屏蔽信号码恢复成原样。
sigsuspend的作用:
在运行一段程序时,我们可能想要让程序暂时的忽略某个信号,而后执行某个代码片断,执行后复原成原来的屏蔽信号码,接受原来可能在屏蔽其间所发出的被屏蔽掉的信号。
我们一开始可能想到的是用sigprocmask 和 pause来完成,代码如下:
点击(此处)折叠或打开
但是这样做有个问题,当信号在pause()之前发出,如果该信号之发送了一次,那进程先会执行一次信号处理函数,然后将会在pause处永久挂起。
为了避免这种BUG,引入了sigsuspend(),该函数操作是一个原子操作,也就是说在执行该于原子操作其间,CPU不会进行线程切换,这样就不会被其它的线程所打断。
修改后的代码如下:
点击(此处)折叠或打开
程序在执行完相应的临界区代码后(此处临界区代码只写了sleep(30),只是为了保证之后在sleep期间收到SIGINT信号,实际中可根据需求加上相应的临界区代码),用sigsuspend接收在临界区发出的信号,借着执行如下的原子操作:
1.屏蔽&zeromask信号集所包含的信号,此处为空,所以可以捕获所有的信号。
2.捕获非屏蔽的信号,此处即捕获所有的信号。
3.执行捕获到的信号所对应的信号处理函数。
4.将当前所屏蔽的信号恢复成执行sigsuspend之前所屏蔽的信号。
执行完4步操作后,程序结束,而不会想之前的程序停在pause()。
sigsuspend在实际中还有很多应用,在此先介绍这一种用法,剩下日后遇到再补充。