【Linux】实现睡眠函数mysleep

1. 普通版本的 mysleep 函数(有 bug 存在)

vim mysleep.c



vim Makefile


运行结果如下:



我们可以发现当我们的代码运行以后,屏幕上输出很多的 using mysleep sleep! ,而且在最后一行每隔三秒打印一次,且一直打印直到我们强制停止。

审视 “mysleep” 程序,设想这样的时序:

1. 注册 SIGALRM 信号的处理函数。

2. 调用 alarm(nsecs) 设定闹钟。

3. 内核调度优先级更高的进程取代当前进程执行,并且优先级更高的进程有很多个,每个都要执行很长时间。

4. nsecs 秒钟之后闹钟超时了,内核发送 SIGALRM 信号给这个进程,处于未决状态。

5. 优先级更高的进程执行完了,内核要调度回这个进程执行。SIGALRM 信号递达,执行处理函数 sig_alrm 之后再次进入内核。

6. 返回这个进程的主控制流程,alarm(nsecs) 返回,调用 pause() 挂起等待。

7. 可是 SIGALRM 信号已经处理完了,还等待什么呢?

        出现这个问题的根本原因是系统运行的时序 (Timing) 并不像我们写程序时所设想的那样。虽然 alarm(nsecs) 紧接着的下一行就是 pause(),但是无法保证 pause() 一定会在调用alarm(nsecs) 之后的 nsecs 秒之内被调用。由于异步事件在任何时候都有可能发生(这里的异步事件指出现更高优先级的进程),如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件 (Race Condition)。

2. 规避竞态条件的 mysleep

vim mysleep.c



运行结果如下:


结果相同,证明我们也实现了 mysleep。


那么我们来分析一下两者的区别:

        第一种 mysleep 的实现我们说存在时序问题,会在某种程度上产生 bug,那么第二种方法是如何规避的呢?它将“解除信号屏蔽”和“挂起等待信号”这两步能合并成一个原子操作,是因为调用了 sigsuspend 函数,sigsuspend 包含了 pause 的挂起等待功能,同时解决了竞态条件的问题,因此在对时序要求严格的场合下都应该调用 sigsuspend 而不是pause。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值