模拟实现Linux下的sleep函数

1. 我们都知道Linux下的sleep是睡眠函数,参数是休眠的时间,今天我们利用alarm函数,pause函数实现mysleep。

  1 #include <stdio.h>
  2 #include <signal.h>
  3 #include <unistd.h>
  4 void sig_alrm(int signo)
  5 {//do nothing
  6 }
  7 int  mysleep(int seconds)
  8 {
  9     struct sigaction new,old;
 10     int unsleep=0;
 11     new.sa_handler=sig_alrm;   //对struct new 对象进行初始化,并指定信号处理动作
 12     sigemptyset(&new.sa_mask);
 13     new.sa_flags=0;
 14                                                                             
 15     sigaction(SIGALRM,&new,&old); //注册信号处理函数
 16     alarm(seconds);               //设置闹钟
 17     pause();                      //将进程挂起
 18     unsleep=alarm(0);             //解除闹钟
 19     sigaction(SIGALRM,&old,NULL); //恢复默认信号处理动作
 20     return unsleep;
 21 }
      int main()
 23 {
 24     while(1)
 25     {
 26         mysleep(5);
 27         printf("5 past ");
 28     }
 29     return 0;
 30 }       

上面实现的这个mysleep 虽然简单,但是是有问题的。

有问题的原因是系统运行的时序(Timing)并不是我们所想的那样,虽然alarm紧接着的下一行就是pause函数,但是无法保证pause一定会在调用alarm之后的seconds之内被调用。由于异步事件在任何时候都有可能发生,则会产生时序问题,时序问题是最难解决的问题之一。它的问题的出现是不定时的。

我们利用sigsuspend函数解决这个问题。

sigsuspend函数包含了pause的挂起等待功能,同时解决了竞态条件问题。

  1  #include <stdio.h>                                                          
  2 #include <signal.h>
  3 #include <unistd.h>
  4 void sig_alar(int signo)
  5 {}
  6 int mysleep(int seconds)
  7 {
  8     struct sigaction  newact,oldact;
  9     sigset_t newmask,oldmask,suspmask;
 10     int unslept;
 11 
 12     newact.sa_handler=sig_alar;  //设置我们的信号处理函数,初始化newact对象
 13     sigemptyset(&newact.sa_mask);
 14     newact.sa_flags=0;
 15     sigaction(SIGALRM,&newact,&oldact);
 16 
 17     sigemptyset(&newmask);
 18     sigaddset(&newmask,SIGALRM);  //设置阻塞信号SIGALRM
 19     sigprocmask(SIG_BLOCK,&newmask,&oldmask);
 20 
 21     alarm(seconds);              //设置闹钟
 22 
 23     suspmask=oldmask;
        sigdelset(&suspmask,SIGALRM);  //确认SIGALRM没有被阻塞
 25     sigsuspend(&suspmask);
 26 
 27     unslept=alarm(0);              //取消闹钟
 28     sigaction(SIGALRM,&oldact,NULL);   //恢复默认信号处理动作
 29 
 30     sigprocmask(SIG_SETMASK,&oldmask,NULL);
 31     return unslept;
 32 }
 33 int main()
 34 {
 35     while(1)
 36     {
 37         mysleep(1);   
       printf("1 seconds pass");
 39     }
 40      return 0;

2. SIGCHLD

我们都知道在一个进程退出后,父进程需要通过wait 和 waitpid 来获取子进程退出的信息,并且回收子进程。

其实,子进程在终止时会给父进程发送SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程就可以只专心自己的工作,不需要一直等待子进程的退出时间。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <signal.h>
  4 void hander(int sig)
  5 {
  6     pid_t id;
  7     while(id=waitpid(-1,NULL,WNOHANG)>0)
  8     {
  9         printf("wait child success:%d\n",id);
 10     }
 11     printf("child quit!",getpid());
 12 }                                                                           
 13 
 14 int main()
 15 {
 16     signal(SIGCHLD,hander);
 17     pid_t pid;
 18     if(pid=fork()==0)
 19     {
 20         printf("child:%d\n",getpid());
 21         sleep(3);
 22         exit(1);
 23     }
      while(1){
 25         printf("father do nothing\n");
 26         sleep(1);
 27     }
 28     return 0;
 29 }          

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值