一、模拟sleep函数
利用pause和alarm以及信号相关接口来模拟sleep函数
1.利用sigaction改变alarm发出的信号的递达方式
2.设置闹钟
3.pause
4.闹钟响了,发送信号
5.pause出错返回
二、代码实现
1.未考虑竞态
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void handler(void* avg)
{
//自定义处理动作:什么也不做!
}
int my_sleep(int timeout)
{
sigset_t set;
sigemptyset(&set);
struct sigaction act ,oact;//创建两种信号处理方式
act.sa_handler = handler;//捕捉信号(自定义函数)
act.sa_mask = set;//信号屏蔽字(是否对某一信号阻塞)
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);//将SIGALRM信号的处理方式改为自定义函数
alarm(timeout);//设置闹钟
pause();//挂起进程,直到有信号递达
int ret = alarm(0);//关闭闹钟
sigaction(SIGALRM,&oact,NULL);//恢复系统默认对SIGALRM信号的处理方式
return ret;
}
int main()
{
while(1){
printf("I am sleeping \n");
my_sleep(2);
}
return 0;
}
上面的代码中如果刚把闹钟设置了之后,进程就被系统切出去,执行更高优先级的进程,而且这个进程执行的时间很长。但此时闹钟响了,发送SIGALRM给进程,该信号处于未决状态,这时系统切回来了,并递达了这个信号。那么下面的pause将不会再收到alarm的信号。
所以,要考虑这种情况。即竞态条件。
2.竞态版本
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)
{
}
int mysleep(int time)
{
sigset_t set,oset,susmask;
sigemptyset(&set);
sigaddset(&set,SIGALRM);
sigprocmask(SIG_BLOCK,&set,&oset);
struct sigaction act;
struct sigaction oact;
act.sa_handler = handler;
act.sa_mask = set;
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);
alarm(time);
susmask = oset;
sigdelset(&susmask,SIGALRM);
sigsuspend(&susmask);
int _time = alarm(0);
sigaction(SIGALRM,&oact,NULL);
sigprocmask(SIG_BLOCK,&oset,NULL);
return _time;
}
int main()
{
while(1){
printf("I am sleeping \n");
my_sleep(2);
}
return 0;
}