Linux环境下模拟实现sleep函数
1.代1
1.代码中用到的库函数、结构体介绍
SIGALRM 信号:
时钟定时信号, 计算的是实际的时间或时钟时间, alarm函数使用该信号。
alarm函数:#include <unistd.h>
unsigned int alarm(unsigned int seconds);
- 1
- 2
#include <unistd.h>
int pause(void);
pause函数使调用进程挂起直到有信号递达。pause只有出错的返回值。errno设置为EINTR表示“被信号中断”。
如果信号的处理动作是终止进程,则进程终止, pause函数没有机会返回;
如果信号的处理动作是忽略,则进程继续处于挂起状态, pause不返回;
如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回- 1;
sigaction函数:#include <signal.h>
int sigaction(int signo, const struct sigaction *act, structsigaction *oact);
2.普通版本的mysleep函数
#include #include #include void handler(int sig) {} int mysleep(int timeout) { struct sigaction act,oact; act.sa_handler=handler; act.sa_flags=0; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&oact); alarm(timeout); pause(); int ret=alarm(0); sigaction(SIGALRM,&oact,NULL); return ret; } int main() { while(1) { printf("using mysleep \n"); mysleep(3); } }
程序运行结果:
部分函数解释:调用alarm(timeout)设定闹钟。 调用pause等待,内核切换到别的进程运行。 timeout秒之后,闹钟超时,内核发SIGALRM给这个进程。
3.避免竞态条件的mysleep
由于时序问题而导致的错误,叫做竞态条件 在普通版本的mysleep程序中,我们设想的时序是 1.注册SIGALRM信号的处理函数 2.调用alarm(n)设定闹钟 3,内核调度优先级更高的进程取代当前进程执行,并且优先级更高的进程有很多个,每个都要执行很长时间 4.n秒钟之后闹钟超时了,内核发送SIGALRM信号给这个进程,处于未决状态 5.优先级更高的进程执行完,内核要调度回这个进程继续执行。SIGALRM信号递达,执行处理函数后再次进入内核 6.返回这个进程的主控制流程,alarm(n)返回,调用pause()挂起等待
由于系统运行代码时并不会按照我们的思路走,虽然alarm(timeout)紧接着的下一行就是pause(),但是无法保证pause()一定
会在调用alarm(timeout)之后的timeout秒之内被调用。
由于异步事件在任何时候都有可能发生,如果写程序时考虑不周密,就可能由于时序问题而导致错误。
只有将“解除信号屏蔽”和“挂起等待信号”两步合并成一个原子操作,才能避免由于竞态条件带来的错误。
sigsuspend函数正好可以完成这个功能。sigsuspend包含了pause的挂起等待功能,同时解决了竞态条件的问题
#include
#include
#include
void handler(int sig)
{}
int mysleep(int timeout)
{
struct sigaction act,oact;
sigset_t mask,omask,suspmask;
unsigned int unslept;
act.sa_handler=handler;
act.sa_flags=0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM,&act,&oact);
sigemptyset(&mask);
sigaddset(&mask,SIGALRM);
sigprocmask(SIG_BLOCK,&mask,&omask);
alarm(timeout);
suspmask=omask;
sigdelset(&suspmask,SIGALRM);
sigsuspend(&suspmask);
int ret=alarm(0);
sigaction(SIGALRM,&oact,NULL);
sigprocmask(SIG_SETMASK,&omask,NULL);
return ret;
}
int main()
{
while(1)
{
printf("using mysleep \n");
mysleep(3);
}
}
1,5 Top
sigsuspend函数是pause函数的增强版。当sigsuspend函数的参数信号集为空信号集时,sigsuspend函数是和pause函数是一样的,可以
接受任何信号的中断。
但,sigsuspend函数可以屏蔽信号,接受指定的信号中断。
sigsuspend函数=pause函数+指定屏蔽信号