竞态条件与sigsuspend,sigchld信号函数

竞态条件与sigsuspend函数

sigsuspend 包含了pause 的挂起等待功能,同时解决了竞态条件的问题,在对时序要求严格的
场合下都应该调用sigsuspend 而不是pause 。
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
和pause 一样,sigsuspend 没有成功返回值,只有执行了一个信号处理函数之后sigsuspend 才返
回,返回值为-1,errno 设置为EINTR 。
调用sigsuspend 时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某
个信号的屏蔽,然后挂起等待,当sigsuspend 返回时,进程的信号屏蔽字恢复为原来的值,如果原
来对该信号是屏蔽的,从sigsuspend 返回后仍然是屏蔽的。

以下用sigsuspend 重新实现mysleep函数:
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction
newact, oldact;
sigset_t
newmask, oldmask, suspmask;
unsigned int
unslept;
/* set our handler, save previous information */
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
/* block SIGALRM and save current signal mask */
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
alarm(nsecs);
suspmask = oldmask;
sigdelset(&suspmask, SIGALRM);
blocked */
sigsuspend(&suspmask);
be caught */
/* some signal has been caught,
/* make sure SIGALRM isn't
/* wait for any signal to
SIGALRM is now blocked */
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);
/* reset previous action
*/
/* reset signal mask, which unblocks SIGALRM */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return(unslept);

}
如果在调用mysleep函数时SIGALRM信号没有屏蔽:
1. 调用sigprocmask(SIG_BLOCK, &newmask, &oldmask); 时屏蔽SIGALRM。
2. 调用sigsuspend(&suspmask);时解除对SIGALRM的屏蔽,然后挂起等待待。
3. SIGALRM递达后suspend返回,自动恢复原来的屏蔽字,也就是再次屏蔽SIGALRM。
4. 调用sigprocmask(SIG_SETMASK, &oldmask, NULL);时再次解除对SIGALRM的屏蔽。


4.7. 关于SIGCHLD信号
进程一章讲过用wait 和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻
塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不
能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一
下,程序实现复杂。
其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自
定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程
终止时会通知父进程,父进程在信号处理函数中调用wait 清理子进程即可。
请编写一个程序完成以下功能:父进程fork 出子进程,子进程调用exit(2)终止,父进程自定
义SIGCHLD信号的处理函数,在其中调用wait 获得子进程的退出状态并打印。
事实上,由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调
用sigaction 将SIGCHLD的处理动作置为SIG_IGN,这样fork 出来的子进程在终止时会自动清理掉,不
会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction 函数自定义的忽略
通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可
用。请编写程序验证这样做不会产生僵尸进程。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值