Linux下,实现一个sleep函数
2017-07-02 10:19
411 查看
alarm函数
首先,想要实现这个sleep函数,就得先做一些铺垫知识,所以就得先了解一下alarm函数,调用alarm函数可以设定一个闹钟,也就是告诉内核(kernel)在seconds秒之后给当前进程发送一个SIGALRM信号,该信号的默认动作是终止当前进程。这个函数的返回值是0,或者离你设定闹钟时间所剩下的秒数。举个简单的例子,你订了一个30分钟的闹钟,如果你一直没被打扰,当半小时后你的闹钟响了,它就返回0值,而当你睡了20分钟时,舍友进来将你吵醒,你还想继续睡,就设定一个20分钟后响的闹钟,这时候就会返回一个10分钟,即就是在你被吵醒到你闹钟本该响之间剩下的时间了。先通过下面的代码熟悉alarm函数
#include<stdio.h> #include<unistd.h> int main() { int count = 1; alarm(1); for(;1;count++) printf("count = %d\n",count); return 0; }
这个理解起来也很简单,count一直++,一秒后被SIGALRM信号终止
运行结果如下。
mysleep实现
了解了alarm函数之后,下面只要搭配使用pause()即让当前进程处于挂起状态。两个函数搭配使用,就可以实现一个简单的mysleep函数了。代码如下:
#include<stdio.h> #include<signal.h> void handler(int signo) { } int mysleep(int second) { struct sigaction act,oact; act.sa_handler = handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&oact); alarm(second); pause(); int ret = alarm(0); sigaction(SIGALRM,&oact,NULL); return ret; } int main() { while(1) { printf("Begin sleep!\n"); mysleep(3); printf("Finish sleep!\n"); printf("\n"); } return 0; }
让程序每次sleep3秒。
运行结果如下:
在每次打印Begin sleep,三秒之后,就会打印一句Finish sleep。换行之后,程序又继续进行下一次sleep了。
改进后的mysleep
那么上面的mysleep函数有没有BUG呢,答案是肯定的,试想下面一个场景,当你定好一个10分钟的闹钟后,本应该10分后给你返回,结果当第九分钟时你这个进程被切出去了(任何时候进程都有可能被切出去),30分钟后将你切回来,但是你闹钟返回信号是在20分钟前的事了,那个时候你是被切出去的,并不能接受到该信号,这就导致程序崩了。那么我们就来重新审视这个问题,编写更为完善的mysleep函数。大致的思想是这样的,我们可以屏蔽该信号,这样不管即使被切出去了,闹钟也不会返回在你这个进程不在的时候返回信号,直到你被切回来才会收到该信号,这样就有效防止了被切除后引起的程序崩溃问题。
下面是改进后的代码:
#include<stdio.h> #include<signal.h> void handler(int signo) {} int mysleep(int second) { struct sigaction act,oact; sigset_t newmask,oldmask,suspmask; act.sa_handler = handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&oact); sigemptyset(&newmask); sigaddset(&newmask,SIGALRM); sigprocmask(SIG_BLOCK,&newmask,&oldmask); alarm(second); suspmask = oldmask; sigdelset(&suspmask,SIGALRM); sigsuspend(&suspmask); int unslept = alarm(0); sigaction(SIGALRM,&oact,NULL); sigprocmask(SIG_SETMASK,&oldmask,NULL); return (unslept); } int main() { while(1) { printf("Begin mysleep\n"); mysleep(3); printf("Finish mysleep\n"); } return 0; }
程序的运行结果肯定是一样的,只是第二种比第一种更加完善。通过实现这个mysleep函数,可以更加清晰的理解alarm函数了。
相关文章推荐
- 收藏的一个linux下proxy实现的源码
- linux下用lex/yacc实现的一个小汇编器,for 体系实习2,实习中唯一可以拿的出来的东西
- 一个Linux下C线程池的实现
- LINUX C实现读取一个文本文件并返回其中最长的行的内容
- 【转载】实现一个简单的linux线程池
- linux下如何实现为一个网卡绑定多个IP地址
- Linux下两个远程登陆用户如何共享同一个登陆shell,以实现远程教育或远程协助
- linux下如何自动检测并重新启动一个死掉的进程(shell脚本实现)
- 一个Linux下C线程池的实现
- linux下如何自动检测并重新启动一个死掉的进程,然后再把它杀死:)(shell脚本实现)
- 在SuSELinuxEnterpriseServer10.1SP1实现一个IP建多个Web
- 在 Fedora 5 Linux 下实现了一个基于 libmad 的 MP3 流媒体播放器
- Linux网络编程:一个简单的正向代理服务器的实现
- 一个进程安全的日志类, Linux实现
- 在linux上实现一个协议栈
- 一个嵌入式Linux系统的键盘驱动实现
- 发一个多线程通过 HTTP 下载文件的类(Linux下的实现)
- 一个Linux下C线程池的实现
- linux下单例进程的一个实现方式
- 一个Linux下C线程池的实现