模拟实现sleep函数
来源:互联网 发布:got7直播软件 编辑:程序博客网 时间:2024/05/19 13:26
一、普通版本下的sleep函数
前面我们学习了pause函数,知道了pause函数的功能是为了挂起当前的进程,直到有信号递达。有问题的可以参见我的上一篇博客:这篇博客将信号讲的很清楚,其中对于pause函数也做了相应的说明。
linux下的信号
今天我就是用这个pause函数来实现一个自己的sleep函数。
具体实现原理如图所示:
实现过程如下:
1、main函数调用了my_sleep函数,mysleep函数注册了SIGALRM信号的处理函数handler。
2、alarm函数设定的是闹钟,调用pause函数进行等待,在times秒之后内核发送SIGALRM信号给进程。
3、发现SIGALRM信号调用它的handler函数,切换到用户态执行handler函数,进入handler函数时SIGALRM信号被自动屏蔽, 从handler函数返回时SIGALRM信号自动解除屏蔽。再返回用户态
4、pause函数返回-1,调用alarm(0)取消闹钟调用sigaction恢复SIGALRM信号以前的处理动作。
具体代码如下:
#include<stdio.h>#include<unistd.h>#include<signal.h>void hander(int sig){}int mysleep(int time){ struct sigaction act,oact; act.sa_handler = hander; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM,&act,&oact); alarm(time); pause(); sigaction(SIGALRM,&oact,&act); int ret = alarm(0); return ret;}int main(){ while(1) { int ret = mysleep(3); printf("mysleep is over ...%d\n",ret); } return 0;}
代码中存在的问题:
调用alarm(seconds)时,这时并没有执行下一条指令pause()使进程挂起,这时若有内核调度优先级更高的进程取代当前进程执行,并且优先级更高的进程有很多个,每个都要执行很长时间。seconds秒之后闹钟超时了,内核发送SIGALRM信号给被取代切出的进程,其信号处于未决状态,当优先级更高的进程执行完了,内核调度会使被取代切出进程执行,这时SIGALRM信号递达,执行其自定义捕捉函数之后再次进入内核;最后返回这个进程的主控制流程,alarm(seconds)返回,再调用pause()挂起等待。
别的进程优先级高影响了此进程调度时间,使alarm()函数seconds秒发送的SIGALRM信号已经处理完成,所以pause使进程挂起后将不会在收到自定义捕捉的信号。
二、规避竞态条件的sleep函数
上面代码问题的根本原因是系统运行的时序(Timing)并不像我们写程序时所设想的那样。虽然alarm(times)紧接着的下一行就是pause(),但是无法保证pause()一定会在调用alarm(times)之后的times秒之内被调用。
由于异步事件在任何时候都有可能发生(这里的异步事件指出现更高优先级的进程),如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件 (Race Condition)。
sigsuspend:
int sigsuspend(const sigset_t *mask);
sigsuspend没有成功返回值,只有执行了一个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。
调用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。
代码展示如下:
#include<stdio.h>#include<unistd.h>#include<signal.h>void hander(int sig){}int mysleep(int time){ struct sigaction act,oact; act.sa_handler = hander; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM,&act,&oact); sigset_t newset,oldset,sigmask; sigemptyset(&newset); sigemptyset(&oldset); sigaddset(&newset,SIGALRM); sigprocmask(SIG_BLOCK,&newset,&oldset); alarm(time); sigmask = oldset; sigdelset(&sigmask,SIGALRM); sigsuspend(&sigmask); sigaction(SIGALRM,&oact,&act); sigprocmask(SIG_SETMASK,&oldset,&newset); int ret = alarm(0); return ret;}int main(){ while(1) { int ret = mysleep(3); printf("mysleep is over ...%d\n",ret); } return 0;}
- 模拟实现sleep函数
- 模拟实现sleep函数
- javascript模拟实现sleep函数
- 【Linux】模拟实现sleep函数
- 【Linux】模拟实现sleep函数
- 【linux】:模拟实现sleep函数
- Linux中模拟实现sleep函数
- Linux环境下模拟实现sleep函数
- LINUX下模拟实现sleep函数
- 模拟实现sleep函数——mysleep()
- 模拟实现sleep方法
- Linux模拟实现sleep
- 在Linux环境下模拟实现sleep函数
- 信号的捕捉与模拟实现sleep函数
- 信号模拟 sleep 函数,定时器
- JS 模拟线程实现sleep
- Linux 信号 模拟实现sleep
- sleep(n)函数实现
- C++之函数返回指针
- 存储的瓶颈(3)
- JSP中实现系统登录后的退出原理及代码 使session失效
- ECLIPSE配置jre
- Java配置----JDK开发环境搭建及环境变量配置
- 模拟实现sleep函数
- 存储的瓶颈(2)
- cookie失效时,应是整个页面返回登陆页面,而不只是iframe里返回,这导致cookie失效了,页面导航栏出现重复
- SQL 左外连接,右外连接,全连接,内连接
- C++打印图形
- Android最简单的数据传递——用户注册
- 负载均衡-Session处理策略
- 存储的瓶颈(1)
- wxPython:图标、菜单、加速键、消息框