编写一个mysleep函数
来源:互联网 发布:淘宝app流量软件 编辑:程序博客网 时间:2024/06/05 00:47
编写实现mysleep函数
在这之前,我写了有关于信号的相关知识,我在里面讲到了两个函数,分别是alarm和pause两个函数,这两个函数是干嘛的呢,我在这里再介绍一遍。
alarm函数
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程。 这个函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。
pause函数
pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为EINTR, 所以pause只有出错的返回值。错误码EINTR表示“被信号中断”。
下面我用alarm和pause实现sleep()函数:
1、main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数sig_alrm()
2、调用alarm(seconds)函数设定闹钟
3、调用pause等待,内核切换到别的线程去运行
4、seconds秒之后,闹钟超时,内核发SIGALRM信号给这个进程
5、在内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm()
6、切换到用户态执行sig_alrm()函数,进入sig_alrm()函数时SIGALRM信号自动被屏蔽,从sig_alrm()函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数)(这里就是之前我提到的信号捕捉,不清楚的可以去看一下(信号的学习))
7、pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理动作。
在看了上面的代码之后,我们可以去运行一下
我们看到这里的效果和实现一个sleep的效果是一致的。
但其实,这里的程序是带有一点小bug的,你可以看出来吗?
给点提示,bug在第26行设置闹钟这里。
我们现在设想一下,给出这样的操作时序:
1、注册SIGALRM信号处理函数
2、调用alarm(seconds)函数设定闹钟
3、内核调度优先级更高的进程替代当前进程执行,并且优先级更高的进程有很多个,每个都需要执行很长的时间
4、seconds秒之后闹钟超时了,内核发送SIGALRM信号给这个进程,处于未决状态
5、优先级更高的进程执行完了,内核要调度这个进程执行。SIGALRM信号递达,执行处理函数sig_alrm()之后再次进入内核
6、返回这个进程的主控制流程,alarm(seconds)返回,调用pause()挂起等待
7、但是,此时SIGALRM信号已经被处理完了,那还需要等待什么呢?
竞态条件和sigsuspend函数
出现这个问题的根本原因是系统运行的时序(Timing)并不像我们写程序时所设想的那样。虽然alarm(seconds)紧接着的下一行就是pause(),但是无法保证pause()一定会在调用alarm(seconds)之后的seconds秒之内被调用。由于异步事件在任何时候都有可能发生(这里的异步事件指出现更高优先级的进程)。如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件 (Race Condition)。
那么在理解这个问题之后,我们应该能够想出这样的处理方法->在调用pause之前屏蔽SIGALRM信号使它不能提前递达就好了。
首先看一下下面的方法:
1、屏蔽SIGALRM信号
2、alarm(seconds)
3、解除对SIGALRM信号的屏蔽
4、pause()
但是呢,从解除信号屏蔽到调用pause之间任然存在间隙,SIGALRM信号任然有可能在这个间隙之间递达。若要消除这个间隙,我们将解除屏蔽移到pause之后可以嘛?
1、屏蔽SIGALRM信号
2、alarm(seconds)
3、pause()
4、解除对SIGALRM信号的屏蔽
这样就更不行了,还没有解除屏蔽就调用pause,pause根本不可能等到SIGALRM信号。
所以,我们还是想要通过第一种方法去处理这个问题,只要将“解除信号屏蔽”和“挂起等待信号”这两步合并成一个原子操作就好了。
所以,这里我再介绍到sigsuspend这个函数,上面的要求正是sigsuspend函数的功能。 sigsuspend包含了pause的挂起等待功能,同时解决了竞态条件的问题,在对时序要求严格的场合下都应该调用sigsuspend而不是pause。
和pause一样,sigsuspend没有成功返回值,只有执行了一个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。
下面我就用sigsuspend去重新实现一下mysleep函数
如果在调用mysleep函数时SIGALRM信号没有屏蔽:
1. 调用sigprocmask(SIG_BLOCK, &mask, &omask);时屏蔽SIGALRM。
2. 调用sigsuspend(&suspmask);时解除对SIGALRM的屏蔽,然后挂起等待待。
3. SIGALRM递达后suspend返回,自动恢复原来的屏蔽字,也就是再次屏蔽SIGALRM。
4. 调用sigprocmask(SIG_SETMASK, &omask, NULL);时再次解除对SIGALRM的屏蔽。
然后我们运行一下程序:
- 编写一个mysleep函数
- 编写mysleep
- 编写mysleep
- 编写mysleep
- Linux信号(二)——编写自己的mysleep函数
- Linux中的mysleep函数
- mysleep与sigsuspend函数
- 实现睡眠函数mysleep
- mysleep
- mysleep
- 实验五:实现mysleep函数
- 【Linux】实现睡眠函数mysleep
- 编写规避竞态条件的mysleep
- unix程序设计实验五 实现mysleep函数
- 【Linux】sleep函数的简单实现--mysleep
- 模拟实现sleep函数——mysleep()
- [Linux]继续探究mysleep函数(竞态条件)
- Linux-MySleep函数实现与竟态条件
- 【caffe-Windows】微软官方caffe之 matlab接口cpu配置
- fargment重叠问题解决
- Android Launcher 专属页和生活页的实现(一)
- 第一次博客,从0开始
- Kafka消息生成,消费,存储机制
- 编写一个mysleep函数
- leetcode 347. Top K Frequent Elements
- ASP.NET加载FTP下的文件
- iptables:应用防火墙规则:ptables-restore: line 1failed [失败]
- Windows Server 2012 网络负载均衡(NLB)
- 爬虫过程中关于IP被封与反扒的策略
- grep的一些用法
- 使用Python求解数独
- css selector