第六章_信号 : 函数sleep

函数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);
}

但是这个解决方案引来一个问题,longjmp会中断其他的信号处理。

一个实验

#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;   //纳秒数
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值