Linux模拟实现sleep函数

 更新时间:2017年04月27日 16:19:36   作者:Hyacinth_Dy  
这篇文章主要为大家详细介绍了Linux模拟实现sleep函数,让程序休眠一定的秒数,到时间后自动恢复运行

先来说说工作原理,linux中的sleep函数能够让程序休眠一定的秒数,到时间后自动恢复运行。

实现思路

设定睡眠的秒数
睡眠(挂起)
恢复运行

实现机制

设定睡眠的秒数:采用alarm()函数设定需要睡眠的秒数,到时间后闹钟会发送SIGALRM信号给当前进程。但SIGALRM信号的默认操作是终止进程,所以我们需要对SIGALRM信号进行自定义处理。
睡眠:pause()函数会让当前进程挂起,直到收到信号才会出错返回。

示例程序代码:模拟实现sleep使当前进程每2秒打印”hello yingying\n”

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)//由于程序在睡眠期间什么也不做所以自定义处理函数不执行任何操作
{
}
int mysleep(int time)
{
 sigset_t set;
 sigemptyset(&set);
 struct sigaction act;
 struct sigaction oact;
 act.sa_handler = handler;//自定义处理函数
 act.sa_mask = set;
 act.sa_flags = 0; 
 sigaction(SIGALRM,&act,&oact);//捕捉闹钟信号自定义处理动作
 alarm(time);//time秒后给进程发送信号
 pause();//挂起进程
 int _time = alarm(0);//如果程序被提前唤醒取消闹钟
 sigaction(SIGALRM,&oact,NULL);//恢复捕捉信号的原始状态
 return _time;
}
int main()
{
 while(1)
 {
 printf("hello yingying\n");
 mysleep(2);
 }
 return 0;
}

问题分析

上述代码在看似没有问题可以实现我们需要的结果,但是带 多执行流下仍可以正常运行吗?例如在设定了闹钟后当前进程被切换出去,等再切换回来闹钟已经响过了,那么当前进程就会被永远挂起。所以我们需要优化上面的程序。

.优化方案一:
1.屏蔽SIGALRM信号
2.alarm(time)
3.解除屏蔽SIGALRM信号
4.pause()

.优化方案二:
1.屏蔽SIGALRM信号
2.alarm(time)
3.pause()
4.解除屏蔽SIGALRM信号

这两种方案大家思考一下可行吗?应该选哪个呢?

方案选择

对于方案一:如果进程在解除屏蔽之后,pause()之前的的间隙被切走仍会造成同样的问题,进程也可能被永远挂起。
对于方案二:程序挂起之后,闹钟信号被屏蔽,一直处于未决状态,程序无法收到信号,进程也就会被一直挂起。所以方案二是不可以选择的。
对于方案一我们可以改进,使解除阻塞与挂起成为一个原子操作这样就可以解决我们的问题了。

解决问题

像方案一这种由时序问题导致程序出现问题的情况成为竞态条件。sigsuspend()函数可以实现pause()函数的挂起功能,同时也能解决竞态条件的问题。sigsuspend()函数的功能就是-“解除信号屏蔽”-“挂起进程等待信号”-“执行信号处理函数”- “出错返回”。所以sigsuspend()函数函数同pause()函数一样只有出错返回值。在对程序时序要求比较严格的程序中一般使用sigsuspend()函数。

优化后的程序代码

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void handler(int signo)
{
}
int mysleep(int time)
{
 sigset_t set,oset,susmask;
 sigemptyset(&set);
 sigaddset(&set,SIGALRM);
 sigprocmask(SIG_BLOCK,&set,&oset);
 struct sigaction act;
 struct sigaction oact;
 act.sa_handler = handler;
 act.sa_mask = set;
 act.sa_flags = 0; 
 sigaction(SIGALRM,&act,&oact);
 alarm(time);
 susmask = oset;
 sigdelset(&susmask,SIGALRM);
 sigsuspend(&susmask);
 int _time = alarm(0);
 sigaction(SIGALRM,&oact,NULL);
 sigprocmask(SIG_BLOCK,&oset,NULL);
 return _time;
}
int main()
{
 while(1)
 {
 printf("hello yingying\n");
 mysleep(2);
 }
 return 0;
}

这样我们的sleep函数的模拟实现就完成了。

程序结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Gunicorn运行与配置方法

    Gunicorn运行与配置方法

    这篇文章主要介绍了Gunicorn运行与配置方法,使用pre-fork worker模式,具有使用非常简单,轻量级的资源消耗,以及高性能等特点。对此感兴趣的朋友跟随小编一起看看吧
    2019-08-08
  • centos6编译及安装ZLMediaKit解析

    centos6编译及安装ZLMediaKit解析

    这篇文章主要介绍了centos6编译及安装ZLMediaKit,需要的朋友可以参考下
    2019-11-11
  • Linux下乱码问题的解决方案小结

    Linux下乱码问题的解决方案小结

    linux系统中文件名内容为urf8编码, windows系统中文件名默认为gbk编码, 多数文档使用gbk编码,系统采用utf8编码.这篇文章主要介绍了Linux下乱码问题的解决方案,需要的朋友可以参考下
    2016-10-10
  • Linux下的chkconfig命令详解

    Linux下的chkconfig命令详解

    大家都知道chkconfig命令在linux中使用是非常的关键的,我们可以利用chkconfig来对系统的一些启动与禁止相关设置,下面这篇文章小编就来给大家详细的介绍Linux下的chkconfig命令用法,有需要的朋友们可以参考学习,下面来一起看看吧。
    2016-11-11
  • Linux下Apache HTTP Server 2.4.26安装教程

    Linux下Apache HTTP Server 2.4.26安装教程

    这篇文章主要为大家详细介绍了Linux下Apache HTTP Server 2.4.26的安装,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • ubuntu下迅雷极速版的安装与使用

    ubuntu下迅雷极速版的安装与使用

    Ubuntu是一个完全基于Linux的操作系统,它不但免费,而且有专业人员和业余爱好者共同为其提供技术支持。迅雷极速版的推出吸引了众多追求速度的网友关注。那么这篇文章我们就来学习下在ubuntu下迅雷极速版与QQ旋风的安装与使用,有需要的朋友们下面来一起看看吧。
    2016-10-10
  • 详解CentOS8更换yum源后出现同步仓库缓存失败的问题

    详解CentOS8更换yum源后出现同步仓库缓存失败的问题

    这篇文章主要介绍了详解CentOS8更换yum源后出现同步仓库缓存失败的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Linux下“/”和“~”的区别详解

    Linux下“/”和“~”的区别详解

    这篇文章主要介绍了Linux下“/”和“~”的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • linux Apache CGI 安装配置

    linux Apache CGI 安装配置

    Apache 中的提交了一种利用扩展应用程序执行动态网页的机制. 称为Common Gateway Interface (通用网关接口)简称CGI.
    2009-05-05
  • Linux使用shell脚本定时删除历史日志文件

    Linux使用shell脚本定时删除历史日志文件

    这篇文章主要介绍了Linux使用shell脚本定时删除历史日志文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08

最新评论