Linux下,实现一个sleep函数

来源:互联网 发布:免费视频编辑软件排行 编辑:程序博客网 时间:2024/05/17 16:13

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函数了。

原创粉丝点击