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函数的模拟实现就完成了。

程序结果

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

相关文章

  • Centos系统下“无法打开并写入文件”问题的解决

    Centos系统下“无法打开并写入文件”问题的解决

    这篇文章主要给大家介绍了关于在Centos系统下报:“无法打开并写入文件”问题的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
    2017-12-12
  • 详解 Linux中的关机和重启命令

    详解 Linux中的关机和重启命令

    这篇文章主要介绍了详解 Linux中的关机和重启命令的相关资料,希望通过此文能帮助到大家掌握这部分内容,需要的朋友可以参考下
    2017-08-08
  • Linux之路由转发和SNAT的应用方式

    Linux之路由转发和SNAT的应用方式

    这篇文章主要介绍了Linux之路由转发和SNAT的应用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Centos7服务器下启动jar包项目的最佳方法

    Centos7服务器下启动jar包项目的最佳方法

    这篇文章主要给大家分享介绍了关于Centos7服务器下启动jar包项目的最佳方法,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • php-fpm 占用CPU过高,100%的解决方法

    php-fpm 占用CPU过高,100%的解决方法

    这篇文章主要介绍了php-fpm 占用CPU过高,100%的解决方法,需要的朋友可以参考下
    2016-09-09
  • Linux 中清空或删除大文件内容的五种方法

    Linux 中清空或删除大文件内容的五种方法

    这篇文章主要介绍了Linux 中清空或删除大文件内容的五种方法的相关资料,需要的朋友可以参考下
    2016-12-12
  • 如何配置apache虚拟主机的实例小结

    如何配置apache虚拟主机的实例小结

    如果你是第一次配置apache虚拟主机,那么通过阅读这篇文章你将会了解到如何实现apache虚拟主机配置。其实要配置好一台虚拟主机没有想象中那么难
    2014-01-01
  • Apache增加最大连接数的方法

    Apache增加最大连接数的方法

    增加Apache最大连接数的方法,需要的朋友可以参考下。
    2011-02-02
  • linux系统下如何挂载NTFS移动硬盘

    linux系统下如何挂载NTFS移动硬盘

    用命令行挂载移动硬盘是Linux的基本操作之一,虽然目前有些Linux系统能自动加载移动硬盘,但有些时候(比如使用Ubuntu Server或其它Linux系统的时候)仍然需要手动操作,下面这篇文章主要介绍了linux系统下如何挂载NTFS移动硬盘,需要的朋友可以参考借鉴。
    2017-01-01
  • 在Debian系的Linux中编译并安装ixgbe驱动的教程

    在Debian系的Linux中编译并安装ixgbe驱动的教程

    这篇文章主要介绍了在Linux中编译并安装ixgbe驱动的教程,采用bash shell、适用于Debian、Ubuntu等各种基于Debian的Linux系统,需要的朋友可以参考下
    2015-03-03

最新评论