linux 下实现sleep详解及简单实例
sleep:
普通版本
1、基本设计思路:
1>注册SIGALRM信号的处理函数;
2>调用alarm(nsecs)设定闹钟;
3>调"htmlcode">
#include<stdio.h> #include<signal.h> void handler(int signo) {} 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 musleep!\n"); mysleep(3); } return 0; }
相关函数分析:
#include <unistd.h> int pause(void);
pause函数使调"htmlcode">
#include <signal.h> int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
sigaction函数可以读取和修改与指定信号相关联的处理动作。调"htmlcode">
int sigemptyset(sigset_t *set);
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表"htmlcode">
#include <signal.h>"color: #ff0000">sigsuspend函数与pause函数:都可以将程序挂起,但是sigsuspend函数可以实现对信号屏蔽字的解除与挂起。sigprocmask
调"htmlcode">
#include <signal.h>"//img.jbzj.com/file_images/article/201706/20176893511849.png" alt="" />
如果调"htmlcode">
#include<stdio.h> #include<signal.h> void handler(int signo) {} int mysleep(int timout) { struct sigaction act,oact; sigset_t newmask,oldmask,suspmask; act.sa_handler = handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&oact); sigemptyset(&newmask); sigaddset(&newmask,SIGALRM); sigprocmask(SIG_BLOCK,&newmask,&oldmask); alarm(timout); suspmask = oldmask; sigdelset(&suspmask,SIGALRM); sigsuspend(&suspmask); int unslept = alarm(0); sigaction(SIGALRM,&oact,NULL); sigprocmask(SIG_SETMASK,&oldmask,NULL); return(unslept); } int main() { while(1) { printf("using musleep!\n"); mysleep(3); } return 0; }优化版本解决了普通版本存在的竞态问题。我们重新审视一下普通版本的时序问题。
1、设置SIGALRM信号的处理函数;
2、调用alarm()函数设置闹钟;
3、内核选取更高优先级的进程来取代当前进程,并且这样的进程很多,同时执行时间又很长;
4、闹钟超时了,内核发送SIGALRM信号给该进程,并且处于未决状态;
5、优先级更高的进程结束后,内核要调度回这个进程执⾏。 SIGALRM信号递达,执⾏处理函 数sig_alrm之后再次进⼊内核。
6、返回这个进程的主控制流程,alarm(nsecs)返回,调⽤pause()挂起等待。
7、可是现在SIGALRM信号已经被处理,进程会导致错误。
在一个进程运行过程中,因为由于异步,所以可能被其他优先级更高的进程,由于时序问题而引发的错误问题。这样的问题称为竞态问题。
优化版本中,先将设置SIGALRM信号的处理函数,然后将SIGALRM信号进行屏蔽,然后调用alarm()函数设置闹钟,然后调用sigprocmask()函数对SIGALRM信号解除屏蔽然后挂起等待,这样就解决了竞态问题。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!