mysleep

来源:互联网 发布:软件开发安卓 编辑:程序博客网 时间:2024/06/05 01:08
                                                       mysleep
普通版本的mysleep:
1、 main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数handler。 
2、调用alarm(time)设定闹钟。 
3、调用pause等待,内核切换到别的进程运行。 
4、time秒之后,闹钟超时,内核发SIGALRM给这个进程。 
5、从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是handler。 
6、切换到用户态执行handler函数,进入handler函数时SIGALRM信号被自动屏蔽, 从handler函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入 内核,再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数)。 
7、pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理 动作。
(1)普通版本mysleep代码如下: 
  
#include<stdio.h>                                                          #include<signal.h>   #include<unistd.h> void handler(int signum)  {}         int mysleep(int time)   {      struct sigaction act,oact;        act.sa_handler=handler;        act.sa_flags=0;       sigset_t sa_mask;     sigemptyset(&sa_mask);       sigaction(SIGALRM,&act,&oact);       alarm(time);     pause();            int ret=alarm(0);      sigaction(SIGALRM,&act,NULL);       return  ret;   }             int main() {       while(1)      {     mysleep(3);          printf("I am sleep,I will sleeping 3 second\n");      }      return 0;         }   

(2)规避竞态mysleep
 
#include<stdio.h>    #include<signal.h>     #include<unistd.h>     #include<stdlib.h>     #include<sys/types.h>                                                     int sigsuspend(const sigset_t *sigmask);  void  handler(int signum)  {}                    int mysleep(int time)   {                      struct sigaction act,oact;   sigset_t newmask,oldmask,suspmask;  act.sa_handler=handler;      act.sa_flags=0;     sigset_t sa_mask;    sigemptyset(&sa_mask);   sigaction(SIGALRM,&act,&oact);   sigemptyset(&newmask);   sigaddset(&newmask,SIGALRM);  sigprocmask(SIG_BLOCK,&newmask,&oldmask);//屏蔽信号SIGALRM   alarm(time);              suspmask=oldmask;               sigdelset(&suspmask,SIGALRM);     sigsuspend(&suspmask);                                                                                 int ret=alarm(0);              sigaction(SIGALRM,&act,NULL);      sigprocmask(SIG_SETMASK,&oldmask,NULL);    return  ret;                 }                                                               int main()                       {                            while(1)                      {                         mysleep(3);                     printf("I am sleep,I will sleeping 3 second\n");     }                          return 0;                                          }     
       
     虽然两个mysleep运行的结果目前表面上都是一样的,但系统运⾏的时序(Timing)并不像我们写程序时所设想的那样。在普通版本中,虽然alarm(time)紧接着的下⼀行就是pause(),但是无法保证pause()一定会在调用alarm(time)之后的time秒之内被调用。 被切换后,若触发SIGALRM信号,信号会立即递达当该进程切回来的时候,接收不到SIGALRM信号,不会再次接收到该信号,线程一直处于挂起状态,得不到激活。在规避竞态版本下,对SIGALRM信号进行了屏蔽,被切出去之后,该信号也不会被递达。因为是原语操作,取消屏蔽字后 ,程序正常激活。