LINUX下实现sleep
来源:互联网 发布:gas mask mac 下载 编辑:程序博客网 时间:2024/06/05 00:10
sleep:
普通版本
1、基本设计思路:
1>注册SIGALRM信号的处理函数;
2>调用alarm(nsecs)设定闹钟;
3>调⽤pause等待,内核切换到别的进程运行;
4>nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程 ;
5>从内核态返回这个进程的⽤户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm;
6> 切换到用户态执行sig_alrm函数,进⼊sig_alrm函数时SIGALRM信号被⾃动屏蔽,从sig_alrm函数返回SIGALRM信 号⾃动解除屏蔽。然后⾃动执⾏系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程(main函数调⽤的mysleep函数);
7>pause函数返回-1,然后调⽤alarm(0)取消闹钟,调⽤sigaction恢复SIGALRM信号以前的处理动作。
2、实现代码
#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函数使调⽤进程挂起直到有信号递达。如果信号的处理动作是终⽌进程,则进程终⽌,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调⽤了信号处理函数之后pause返回-1,errno设置为EINTR,所以pause只有出错的返回值 。
sigaction函数#include <signal.h>int sigaction(int signo, const struct sigaction *act, structsigaction *oact);sigaction函数可以读取和修改与指定信号相关联的处理动作。调⽤成功则返回0,出错则返回- 1。signo是指定信号的编号。若act指针⾮空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。
int sigemptyset(sigset_t *set);
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表⽰该信号集不包含 任何有效信号。
二、优化版本
所需函数分析
#include <signal.h> int sigsuspend(const sigset_t *sigmask);sigsuspend没有成功返回值,只有执⾏了⼀个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。调⽤sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某 个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,sigsuspend返回后仍然是屏蔽的。
sigsuspend函数与pause函数:都可以将程序挂起,但是sigsuspend函数可以实现对信号屏蔽字的解除与挂起。
sigprocmask
调⽤函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。
#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oset);如果oset是⾮空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是⾮空指针,则 更改进程的信号屏蔽字,参数how指⽰如何更改。如果oset和set都是⾮空指针,则先将原来的信号 屏蔽字备份到oset⾥,然后根据set和how参数更改信号屏蔽字。
how的选项意义
如果调⽤sigprocmask解除了对当前若⼲个未决信号的阻塞,则在sigprocmask返回前,⾄少将其中⼀个信号递达。
代码实现:
#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信号解除屏蔽然后挂起等待,这样就解决了竞态问题。
- LINUX下实现sleep
- Linux环境下模拟实现sleep函数
- LINUX下模拟实现sleep函数
- Linux下,实现一个sleep函数
- Linux下使用sleep
- Linux模拟实现sleep
- 在Linux环境下模拟实现sleep函数
- linux下模拟实现sleep以及sleep会出现的问题解决方案
- QT下sleep的实现
- js下的sleep实现
- linux下sleep命令详解
- linux下使用sleep()函数
- linux下c++sleep函数
- Linux 信号 模拟实现sleep
- 【Linux】模拟实现sleep函数
- 【Linux】模拟实现sleep函数
- 【linux】:模拟实现sleep函数
- linux下用select实现精确到睡眠时间小于1秒的sleep函数
- 硬编码与软编码
- 《数据结构学习与实验指导》2-6:数列求和
- 如何将从数据库中读出的带有html标签的字符串,让标签起效,显示在前台页面
- FastDFS & Nginx install
- Maven的下载 安装 环境配置
- LINUX下实现sleep
- Multi-Programming-9 非线程安全类实现生产者和消费者
- #pragma warning 指令集
- Git使用详细教程
- ubuntu误删文件造成软件包信息列表损坏无法更新或安装文件
- 关于typeAliases标签理解 自己挖的坑啊,解决了好久的问题。
- 半夜三更搞不同长度字符对齐问题,头痛
- 1_字符设备驱动程序之LED驱动程序
- 蓝牙模块DIY A09 HC-05主从机一体蓝牙模块 无线蓝牙 串口透传