函数sleep
该函数用于让调用进程挂起,直到
➢ 已经过了指定的时间,或者
➢ 调用进程捕捉到一个信号,并从信号处理程序返回
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
返回值:
➢ 若已经过了指定的时间,则返回0
➢ 若调用进程捕捉到一个信号,并从信号处理程序返回,则sleep提前返回,返回值是未睡够的秒数
示例程序
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int num)
{
printf("\nrecevive the signal is %d\n", num);
}
int main()
{
int time = 20;
signal(SIGINT, sig_handler);
printf("go to sleep.\n");
sleep(time);
printf("sleep is over , I am over.\n");
exit(0);
}
从结果可以分析出,键入中断键后,信号函数被捕获,程序从睡眠中返回,直接执行sleep的下一条语句。
sleep函数的实现方式一
➢ Solaris 9使用alarm实现sleep函数
#include<signal.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
static void sig_alrm(int signo){
return ;
}
unsigned int sleep1(unsigned int nsecs)
{
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
return(nsecs);
alarm(nsecs); //start the time
pause(); //next caught signal wakes us up
return (alarm(0)); //turn off timer,return unslept time
}
int main()
{
int time = 20;
signal(SIGINT, sig_alrm);
printf("go to sleep.\n");
sleep1(time);
printf("sleep is over , I am over.\n");
exit(0);
}
对于问题1
➢ 检查第一次调用alarm的返回值,若其小于本次调用alarm的参数值,则只应等到上次设置的计时器超时;
➢ 若上次设置的计时器超时时间晚于本次设置值,则在sleep1函数返回前,复位此计时器,使其在上次计时器的设定时间再次发生超时
对于问题2
➢ 保存signal函数的返回值,在返回前复位原配置
对于问题3
➢ 可以使用setjmp,或者
➢ sigprocmask、sigsuspend
针对第三个问题的解决方案(alarm和pause之前会存在竞争。具体来说就是,在一个繁忙的系统中,可能执行了alarm之后就切换到其他进程了。可能要在alarm超时之后才调用到pause,那pause不就死定了吗?)
#include<signal.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<setjmp.h>
static jmp_buf env_alrm;
static void sig_alrm(int signo){
longjmp(env_alrm,1);
}
unsigned int sleep1(unsigned int nsecs)
{
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
return(nsecs);
if(setjmp(env_alrm)==0){
alarm(nsecs);
pause();
}
return (alarm(0)); //turn off timer,return unslept time
}
int main()
{
int time = 20;
signal(SIGINT, sig_alrm);
printf("go to sleep.\n");
sleep1(time);
printf("sleep is over , I am over.\n");
exit(0);
}
一个实验
#include<signal.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<setjmp.h>
static jmp_buf env_alrm;
static void sig_int(int signo);
static void sig_alrm(int signo){
longjmp(env_alrm,1);
}
unsigned int sleep2(unsigned int nsecs)
{
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
return(nsecs);
if(setjmp(env_alrm)==0){
alarm(nsecs);
pause();
}
return (alarm(0)); //turn off timer,return unslept time
}
int main(void)
{
unsigned int unslept;
if (signal(SIGINT, sig_int) == SIG_ERR)
printf("signal error");
unslept = sleep2(3);
printf("sleep2 returned: %u\n", unslept);
exit(0);
}
static void sig_int(int signo)
{
int i,j;
volatile int k;
printf("\nsig_int starting\n");
for (i = 0; i < 30000000; i++)
for (j = 0; j < 4000; j++)
k += i * j;
printf("sig_int finished\n");
}
上述程序运行后,立即键入Ctrl+c 程序输出
Sig_int strarting
Sleep2 returned: 0
因为SIGINT的处理并未结束,就被longjmp中断了
sleep函数的实现方式二
➢ FreeBSD、Linux使用nanosleep提供时间延迟
nanosleep函数
该函数挂起调用者线程,直到超时或者接收到信号
#include <time.h>
int nanosleep(const struct timespec* rqtp, struct timespec* rmtp);
timespec结构体
struct timespec {
time_t tv_sec; //秒数
long tv_nsec; //纳秒数
};