linux mysleep实现

来源:互联网 发布:macbook软件怎么下载 编辑:程序博客网 时间:2024/06/05 02:51

一、模拟sleep函数
利用pause和alarm以及信号相关接口来模拟sleep函数
1.利用sigaction改变alarm发出的信号的递达方式
2.设置闹钟
3.pause
4.闹钟响了,发送信号
5.pause出错返回
二、代码实现
1.未考虑竞态

#include <stdio.h>#include <signal.h>#include <unistd.h>void handler(void* avg){                    //自定义处理动作:什么也不做!}int my_sleep(int timeout){    sigset_t set;    sigemptyset(&set);    struct sigaction act ,oact;//创建两种信号处理方式    act.sa_handler = handler;//捕捉信号(自定义函数)    act.sa_mask = set;//信号屏蔽字(是否对某一信号阻塞)    act.sa_flags = 0;    sigaction(SIGALRM,&act,&oact);//将SIGALRM信号的处理方式改为自定义函数    alarm(timeout);//设置闹钟    pause();//挂起进程,直到有信号递达    int ret = alarm(0);//关闭闹钟    sigaction(SIGALRM,&oact,NULL);//恢复系统默认对SIGALRM信号的处理方式    return ret;}int main(){    while(1){    printf("I am sleeping \n");    my_sleep(2);    }    return 0;}

上面的代码中如果刚把闹钟设置了之后,进程就被系统切出去,执行更高优先级的进程,而且这个进程执行的时间很长。但此时闹钟响了,发送SIGALRM给进程,该信号处于未决状态,这时系统切回来了,并递达了这个信号。那么下面的pause将不会再收到alarm的信号。
所以,要考虑这种情况。即竞态条件。
2.竞态版本

#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("I am sleeping \n");    my_sleep(2);    }    return 0;}
0 0