1.编写代码实现sleep功能
利用pause()和alarm()函数来实现
<1> 用alarm()设置闹钟
#include<unistd.h>
unsigned int alarm(unsigned seconds);
alarm函数可以设置一个闹钟,及让内核在seconds秒之后发送一个SIGALRM信号该信号的默认处理动作是终止该进程;
<2> 用pause()等待,内核切换到其他进程运行
#include<unistd.h>
int pause(void)
pause函数使调⽤进程挂起直到有信号递达。如果信号的处理动作是终⽌进程,则进程终⽌,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调⽤了信号处理函数之后pause返回-1,errno设置为EINTR, 所以pause只有出错的返回值。
//mysleep代码
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sig_alrm()
{
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction new,old;
unsigned int unslept = 0;
new.sa_handler=sig_alrm;
sigemptyset(&new.sa_mask);
new.sa_flags=0;
sigaction(SIGALRM,&new,&old);//注册信号处理函数
alarm(nsecs);//设置闹钟
pause();
unslept=alarm(0);//清空闹钟
sigaction(SIGALRM,&old,NULL);//恢复默认信号处理函数
return unslept;
}
int main()
{
while(1)
{
mysleep(1);
printf("5 second passed\n");
}
return 0;
}
<3> sigaction函数
#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
sigaction函数可以读取和修改与指定信号相关联的处理动作。调⽤成功则返回0,出错则返回- 1。 signo是指定信号的编号。若act指针⾮空,则根据act修改该信号的处理动作。若oact指针⾮ 空,则通过oact传出该信号原来的处理动作。
sigaction结构体:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
2.竞态条件下mysleep
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sig_alrm()
{
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction new,old;
sigset_t newmask,oldmask,suspmask;
unsigned int unslept = 0;
new.sa_handler=sig_alrm;
sigemptyset(&new.sa_mask);
new.sa_flags=0;
sigaction(SIGALRM,&new,&old);
sigemptyset(&newmask);
sigaddset(&newmask,SIGALRM);
sigprocmask(SIG_BLOCK,&newmask,&oldmask);
alarm(nsecs);
suspmask=oldmask;
sigdelset(&suspmask,SIGALRM);
sigsuspend(&suspmask);
unslept=alarm(0);
sigaction(SIGALRM,&old,NULL);
sigprocmask(SIG_SETMASK,&oldmask,NULL);
return unslept;
}
int main()
{
while(1)
{
mysleep(1);
printf("5 second passed\n");
}
return 0;
}