利用alarm和pause实现sleep函数的时候有一个问题,如果系统负载比较严重,在执行玩alarm之后CPU被别的进程抢走了,而且抢走的时间比较长,过了alarm的时间了,此时时间一到发送信号,系统肯定立刻处理信号,但之后执行到pause函数之后,信号已经被发送执行了,此时再调用pause就会一直等待,不会被唤醒了,此时就引出了时序竞态问题。
解决办法:使用sigsuspend函数原子操作替代pasue函数,执行alarm函数执行设置对SIGALRM信号的屏蔽,然后执行完alarm函数之后,使用sigsuspend函数解除对SIGALRM信号的屏蔽,这样就不会出现时序竞态问题了,具体代码如下
int my_sleep(int seconds){
struct sigaction newact,oldact;
int lefttime;
newact.sa_handler = sig_alrm;
sigemptyset(&(newact.sa_mask));
newact.sa_flags = 0;
sigaction(SIGALRM,&newact,&oldact);
//先设置SIGALRM信号的屏蔽
sigset_t newmask,oldmask,susmask;
sigemptyset(&newmask);
sigaddset(&newmask,SIGALRM);
sigprocmask(SIG_BLOCK,&newmask,&oldmask);
alarm(seconds); //seconds秒过去之后,发送一个SIGALRM信号
//使用sigsuspend()函数替换pause()函数
susmask = oldmask;
sigdelset(&susmask,SIGALRM); //解除对SIGALRM信号的屏蔽
sigsuspend(&susmask); //使用sigsuspend()函数原子操作来避免时序问题
//pause();
lefttime = alarm(0);
//恢复原状,保证程序的安全性
sigaction(SIGALRM,&oldact,NULL);
sigprocmask(SIG_SETMASK,&oldmask,NULL);
return lefttime;
}