Linux中模拟实现sleep函数

来源:互联网 发布:贵州大数据发展报告 编辑:程序博客网 时间:2024/05/19 00:48

sleep函数原理:当前进程挂起指定时间后继续运行
1、进程挂起
pause():进程挂起,直到收到一个信号,只有出错返回。
2、计时机制()
alarm():设定⼀一个闹钟,也就是告诉内核在seconds秒之后给当前进程发
SIGALRM信号, 该信号的默认处理动作是终⽌止当前进程。这个函数的返回值是0或者是以前设定的闹钟时间还余下 的秒数.
具体实现代码如下:

#include<stdio.h>#include<unistd.h>#include<signal.h>void handler(int signo){}int mysleep(int time){    struct sigaction act,oact;    act.sa_handler = handler;    sigemptyset(&act.sa_mask);    act.sa_flags = 0;    int ret = 0;    sigaction(SIGALRM,&act,&oact);    alarm(time);    pause();    ret = alarm(0);    sigaction(SIGALRM,&oact,NULL);    return ret;}int main(){    while(1)    {        mysleep(1);        printf("I am awake....!\n");    }}

但是在这个函数中,进程执行过程中,设定玩闹钟后,进程被切换了,当进程再次被切换回来时,闹钟时间有可能已经过了,这样pause()再也接收不到SIGALRM 信号,进程将永远挂起,我们可以这样做,在调用pause之前屏蔽SIGALRM信号使它不能提前递达就可以了有如下解决办法:
1. 屏蔽SIGALRM信号;
2. alarm(nsecs);
3. 解除对SIGALRM信号的屏蔽;
4. pause();
从解除信号屏蔽到调⽤用pause之间存在间隙,SIGALRM仍有可能在这个间隙递达。要消除这个间隙, 我们把解除屏蔽移到pause后⾯:
1. 屏蔽SIGALRM信号;
2. alarm(nsecs);
3. pause();
4. 解除对SIGALRM信号的屏蔽;
这样更不行了,还没有解除屏蔽就调⽤pause,pause根本不可能等到SIGALRM信号。要是“解除信号屏蔽”和“挂起等待信号”这两步能合并成⼀个原⼦子操作就好了。
sigsuspend函数就具有这样的功能:
int sigsuspend(const sigset_t *sigmask);
调用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除 对某 个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。
下面用sigsuspend函数重新实现sleep函数:

#include<stdio.h>#include<unistd.h>#include<signal.h>void handler(int signo){}int mysleep(int time){    struct sigaction act,oact;    sigset_t mask,omask,susmask;    act.sa_handler = handler;    sigemptyset(&act.sa_mask);    act.sa_flags = 0;    int ret;    sigaction(SIGALRM,&act,&oact);    sigemptyset(&mask);    sigaddset(&mask,SIGALRM);    sigprocmask(SIG_BLOCK,&mask,&omask);    alarm(time);    susmask = omask;    sigdelset(&susmask,SIGALRM);    sigsuspend(&susmask);    ret = alarm(0);    sigaction(SIGALRM,&oact,NULL);    sigprocmask(SIG_SETMASK,&omask,NULL);    return ret;}int main(){    while(1)    {        mysleep(1);        printf("I am awake....!\n");    }}
0 0
原创粉丝点击