信号函数编写研究

APUE读书笔记

ToDoList

  • [ ] sleep初级实现 2017年12月6日 10:41:30
  • [ ] sleep进阶实现
  • [ ] sleep高阶实现
  • [ ] sleep内核具体实现

第十章

项目 时间 文档版本 作者 备注
读书笔记 2017/12/06 初稿 [email protected] 添加第十章内容

[TOC]


1 编写目的

之前对singnal信号理解一知半解,就这篇文章想通过我的描述来把signal这一章节,深入浅出的讲解出来.

不妨我们就从apue书中具体用例展开我们需要的描述,虽然片面,后续仍会有修改和添加,

2 sleep函数基于信号实现,循序渐进的几个用例

2.1.1 sleep初级实现

2.1.2 代码

static void sig_alrm(int signo){
    /* nothing to do, just return to wake up the pause */
}

unsigned int sleep1(unsigned int nsecs){
    if (signal(SIGALRM, sig_alrm) == SIG_ERR)
        return(nsecs);
    alarm(nsecs);       /* start the timer */
    pause();            /* next caught signal wakes us up */
    return(alarm(0));   /* turn off timer, return unslept time */
}

2.1.2问题
  • 1.如果调用者已设置了闹钟,则它被sleep1函数中的第一次alarm调用擦去
  • 2.该程序中修改了对SIGALRM的配置。
  • 3.在调用 alarm和pause之间有一个竞态条件。

2.1.3解决办法

  • 1.利用alarm返回值确定上次信号状态
  • 2.利用signal返回值确定signal函数原始回调操作
  • 3.利用setjmp和longjmp修改

2.1.4 详细分析

问题 1
利用alarm返回值记录 剩余时钟

可用下列方法更正这一点:检查第一次调用alarm的返回值,如其小于本次调用 alarm的参数值,则只应等到该前次设置的闹钟时间超时。如果前次设置闹钟时间的超时时刻后于本次设置值,则在sleep1函数返回之前,再次设置闹钟时间,使其在预定时间再发生超时。

问题1代码实现


问题 2
该程序中修改了对SIGALRM的配置。

在一个繁忙的系统中,可能 a l a r m在调用 p a u s e之前超时,并调用了信号处理程序。如果发生了这种情况,则在调用 p a u s e后,如果没有 捕捉到其他信号,则调用者将永远被挂起.

没有对原信号处理程序做保存 修改信号掩码 对未决信号 做特殊处理=
可用下列方法更正这一点:检查第一次调用 alarm的返回值,如其小于本次调用 alarm的参数值,则只应等到该前次设置的闹钟时间超时。如果前次设置闹钟时间的超时时刻后于本次设置值,则在sleep1函数返回之前,再次设置闹钟时间,使其在预定时间再发生超时。

问题 2代码实现



问题 3
**在调用 alarm和pause之间有一个竞态条件。 **

在一个繁忙的系统中,可能 a l a r m在调用 p a u s e之前超时,并调用了信号处理程序。如果发生了这种情况,则在调用 p a u s e后,如果没有 捕捉到其他信号,则调用者将永远被挂起

** 利用setjmp和longjmp函数切换上下文**
SVR2中的sleep实现使用了setjmp和longjmp (见7 . 1 0节)以避免问题( 3 )中所说明的竞态条件。
此函数的一个简化版本,称为 s l e e p 2,示于程序 1 0 - 5中(为了缩短实例长度,程序中没有处理
上面所说的问题( 1 )和( 2 )

问题 3代码实现

这部分比较复杂,我们放到下一章节单独来讲

10.8

sleep进阶实现

代码

static jmp_buf  env_alrm;

static void
sig_alrm(int signo)
{
    printf("时钟信号来了,我进入了信号回调函数 sig_alrm\n");
    printf("我尝试了longjmp(env_alrm, 1);再次跳转到主调函数 \n");
    longjmp(env_alrm, 1);// 通常第二个参数都默认写成1
    printf("跳出了 sig_alrm\n");//此行代码无效
}




// 避免了pause函数和alarm韩寒苏竞争
unsigned int
sleep2(unsigned int nsecs)
{
    if (signal(SIGALRM, sig_alrm) == SIG_ERR)  
        return(nsecs);
    if (setjmp(env_alrm) == 0) { // 设置一个longjmp的标签  返回值为0表示成功完成了设置
       // 我设置了一个 
        printf("我成功的设置了 setjmp(env_alrm) \n");
        printf("我设置了一个 %d 秒的闹钟信号\n",nsecs);
        alarm(nsecs);       /* start the timer */   // 来个闹钟实时  如果时钟信号来了  那么代码跳到25行重新来过 避免了alarm先调用 后面pause没法结束
        printf("成功定时向本进程发送一个时钟信号\n");
        printf("在此pause等待时钟信号.......\n\n\n");
        pause();            /* next caught signal wakes us up */
    }
    return(alarm(0));       /* turn off timer, return unslept time */
}


st=>start: Start 
io=>inputoutput: verification 
op=>operation: Your Operation 
cond=>condition: Yes or No? 
e=>end

st->io->op->cond 
cond(yes)->e 
cond(no)->io 

你可能感兴趣的:(信号函数编写研究)