工作原理
linux中的sleep函数能够让程序休眠一定的秒数,到时间后自动恢复运行。
实现思路
设定睡眠的秒数
睡眠(挂起)
恢复运行
实现机制
设定睡眠的秒数:采用alarm()函数设定需要睡眠的秒数,到时间后闹钟会发送SIGALRM信号给当前进程。但SIGALRM信号的默认操作是杀死进程,所以我们需要对SIGALRM信号进行自定义处理。
睡眠:pause()函数会让当前进程挂起,直到收到信号才会出错返回。
示例程序代码:模拟实现sleep使当前进程每2秒打印”hello yingying\n”
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)
{
}
int mysleep(int time)
{
sigset_t set;
sigemptyset(&set);
struct sigaction act;
struct sigaction oact;
act.sa_handler = handler;
act.sa_mask = set;
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);
alarm(time);
pause();
int _time = alarm(0);
sigaction(SIGALRM,&oact,NULL);
return _time;
}
int main()
{
while(1)
{
printf("hello yingying\n");
mysleep(2);
}
return 0;
}
- 问题分析
上述代码在看似没有问题可以实现我们需要的结果,但是带 多执行流下仍可以正常运行吗?例如在设定了闹钟后当前进程被切换出去,等再切换回来闹钟已经响过了,那么当前进程就会被永远挂起。所以我们需要优化上面的程序。
.优化方案一:
1.屏蔽SIGALRM信号
2.alarm(time)
3.解除屏蔽SIGALRM信号
4.pause()
.优化方案二:
1.屏蔽SIGALRM信号
2.alarm(time)
3.pause()
4.解除屏蔽SIGALRM信号
这两种方案大家思考一下可行吗?应该选哪个呢? 方案选择
对于方案一:如果进程在解除屏蔽之后,pause()之前的的间隙被切走仍会造成同样的问题,进程也可能被永远挂起。
对于方案二:程序挂起之后,闹钟信号被屏蔽,一直处于未决状态,程序无法收到信号,进程也就会被一直挂起。所以方案二是不可以选择的。
对于方案一我们可以改进,使解除阻塞与挂起成为一个原子操作这样就可以解决我们的问题了。
解决问题
像方案一这种由时序问题导致程序出现问题的情况成为竞态条件。sigsuspend()函数可以实现pause()函数的挂起功能,同时也能解决竞态条件的问题。sigsuspend()函数的功能就是-“解除信号屏蔽”-“挂起进程等待信号”-“执行信号处理函数”- “出错返回”。所以sigsuspend()函数函数同pause()函数一样只有出错返回值。在对程序时序要求比较严格的程序中一般使用sigsuspend()函数。
优化后的程序代码
#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("hello yingying\n");
mysleep(2);
}
return 0;
}
这样我们的sleep函数的模拟实现就完成了。
- 程序结果
-
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)