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 }