linux 下实现sleep详解及简单实例
sleep:
普通版本
1、基本设计思路:
1>注册SIGALRM信号的处理函数;
2>调用alarm(nsecs)设定闹钟;
3>调⽤pause等待,内核切换到别的进程运行;
4>nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程 ;
5>从内核态返回这个进程的⽤户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm;
6> 切换到用户态执行sig_alrm函数,进⼊sig_alrm函数时SIGALRM信号被⾃动屏蔽,从sig_alrm函数返回SIGALRM信 号⾃动解除屏蔽。然后⾃动执⾏系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程(main函数调⽤的mysleep函数);
7>pause函数返回-1,然后调⽤alarm(0)取消闹钟,调⽤sigaction恢复SIGALRM信号以前的处理动作。
2、实现代码
#include<stdio.h> #include<signal.h> void handler(int signo) {} int mysleep(int timeout) { struct sigaction act,oact; act.sa_handler = handler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGALRM,&act,&oact); alarm(timeout); pause(); int ret = alarm(0); sigaction(SIGALRM,&oact,NULL); return ret; } int main() { while(1) { printf("using musleep!/n"); mysleep(3); } return 0; }
相关函数分析:
#include <unistd.h> int pause(void);
pause函数使调⽤进程挂起直到有信号递达。如果信号的处理动作是终⽌进程,则进程终⽌,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调⽤了信号处理函数之后pause返回-1,errno设置为EINTR, 所以pause只有出错的返回值 。
sigaction函数
#include <signal.h> int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
sigaction函数可以读取和修改与指定信号相关联的处理动作。调⽤成功则返回0,出错则返回- 1。 signo是指定信号的编号。若act指针⾮空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。
int sigemptyset(sigset_t *set);
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表⽰该信号集不包含 任何有效信号。
二、优化版本
所需函数分析
#include <signal.h> int sigsuspend(const sigset_t *sigmask);
sigsuspend没有成功返回值,只有执⾏了⼀个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。调⽤sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某 个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,sigsuspend返回后仍然是屏蔽的。
新闻热点
疑难解答