可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑,但无论如何设置,程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应该使用sigsuspend替换pause信号被解除屏蔽和进程挂起等待(sigsuspend函数执行)是同时进行的,为原子操作,不可分割。

int sigsuspend(const sigset_t *mask);    //其作用与返回值都与pause函数一样(-1,EINTR)。

sigsuspend函数调用期间,进程信号屏蔽字由其参数mask指定,该mask代替了PCB中的信号屏蔽字,当函数执行完(即返回-1)后,信号屏蔽字才会恢复作用。

可将某个信号(如SIGALRM)从临时信号屏蔽字mask中删除,这样在调用sigsuspend时将解除对该信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值。如果原来对该信号是屏蔽态,sigsuspend函数返回后仍然屏蔽该信号。

在单核处理器中,一条指令能完成的操作是原子的(read、write、printf对应N多条汇编指令自然不是原子操作),因为中断是发生指令之间的。多条指令之间基本都是通过lock来实现原子操作,将这多条指令绑定为一个整体,不可分割,即原语。原语就是由若干条指令组成的,用于完成一定功能的一个过程,原语在执行过程中不允许被中断(类似一条指令)。原语在系统态下执行,常驻内存。在内核中有许多原语,如进程创建原语creat、挂起原语suspend、激活原语active、阻塞原语block和唤醒原语wakeup等。sigsuspend函数是一个系统调用,系统调用都是一个原子操作,sigsuspend系统调用实现进程的挂起和信号屏蔽的解除。

//mysleep函数的改进

#include <unistd.h>
#include <signal.h>
#include <stdio.h>void sig_alrm(int signo)
{/* nothing to do */
}unsigned int mysleep(unsigned int nsecs)
{struct sigaction newact, oldact;sigset_t newmask, oldmask, suspmask;unsigned int unslept;//1.为SIGALRM设置捕捉函数,一个空函数newact.sa_handler = sig_alrm;sigemptyset(&newact.sa_mask);newact.sa_flags = 0;sigaction(SIGALRM, &newact, &oldact);//2.设置阻塞信号集,阻塞SIGALRM信号sigemptyset(&newmask);sigaddset(&newmask, SIGALRM);sigprocmask(SIG_BLOCK, &newmask, &oldmask);   //信号屏蔽字mask//3.定时n秒,到时后可以产生SIGALRM信号alarm(nsecs);/*4.构造一个调用sigsuspend临时有效的阻塞信号集,*  在临时阻塞信号集里解除SIGALRM的阻塞*/suspmask = oldmask;sigdelset(&suspmask, SIGALRM);/*5.sigsuspend调用期间,采用临时阻塞信号集suspmask替换原有阻塞信号集*  这个信号集中不包含SIGALRM信号,同时挂起等待,*  当sigsuspend被信号唤醒返回时,恢复原有的阻塞信号集*/sigsuspend(&suspmask);unslept = alarm(0);//6.恢复SIGALRM原有的处理动作,呼应前面注释1(思想)sigaction(SIGALRM, &oldact, NULL);//7.解除对SIGALRM的阻塞,呼应前面注释2(思想)sigprocmask(SIG_SETMASK, &oldmask, NULL);return(unslept);
}int main(void)
{while(1){mysleep(2);printf("Two seconds passed\n");}return 0;
}

时序竞态总结

竞态条件,跟系统负载有很紧密的关系,体现出信号的不可靠性。系统负载越严重,信号不可靠性越强。不可靠由其实现原理所致。信号是通过软件方式实现(跟内核调度高度依赖,延时性强),每次系统调用结束后,或中断处理处理结束后,需通过扫描PCB中的未决信号集,来判断是否应处理某个信号。当系统负载过重时,会出现时序混乱。

其本质原因就是进程随时都有可能会失去CPU,失去CPU时间太长导致信号的处理与进程中主控程序的执行顺序发生了改变,从而产生了不符合预期的结果,出现错误。如上面的pause函数本应该在信号处理之前进行,但是延时太长,导致pause函数执行时,信号提前被处理了。这都是因为信号的处理与主控程序的执行时序不一样产生了不一样的结果。这种错误只有程序员提前遇见,主动规避。

这种意外情况只能在编写程序过程中,提早预见,主动规避,而无法通过gdb程序调试等其他手段弥补。且由于该错误不具规律性,后期捕捉和重现十分困难。

sigsuspend函数(mysleep函数的改进)相关推荐

  1. python之路--嵌套函数、匿名函数、高阶函数。函数的递归

    嵌套函数 函数里不仅可以写代码,还可以嵌套函数 name = "小猿圈"def change():name = "小猿圈,自学编程"def change2(): ...

  2. lambda函数,函数符_为什么您永远不应该在Lambda函数中使用print()

    lambda函数,函数符 两个Lambda用户的故事 (A Tale of Two Lambda Users) 故事1:业余 (Tale #1: The Amateur) One moment eve ...

  3. php 合并数组 效率,PHP将两个关联数组合并函数-增高函数效率

    PHP将两个关联数组合并函数---提高函数效率 在foreach中循环查询数据代码量比较少,但是性能比较低,好点的解决办法是将id收集起来,用in一次性查询,但是这引发了数据结构不是我们用PHP自带的 ...

  4. matlab meshc函数_MATLAB函数库大全(收藏版)

    转发朋友圈获30赞,截图发送至公众号对话框,即可获该文章的PDF版本方便阅读. 目录 1 常用命令 表1.1 管理用命令 表1.2管理变量与工作空间用命令 表1.3文件与操作系统处理命令 表1.4窗口 ...

  5. python函数一----函数基础

    函数 函数(function)就是用于完成特定功能的代码块 使用函数的原因: 增强代码的复用性 封装代码的实现,保护数据的安全 函数的创建 在python中定义函数要使用关键字def,使用return ...

  6. Java箭头函数,lambda函数

    Java箭头函数,lambda函数 lambda表达式实质就是一种语法糖,(建议尽量不要使用lambda表达式,代码太简洁,难懂,难以调试) lambda表达式的简单例子: 不需要参数,返回5 ()- ...

  7. C++ 笔记(13)— 函数(函数声明、函数定义、函数调用[传值、指针、引用]、函数参数默认值、函数重载)

    每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数. 1. 函数声明 函数声明告诉编译器函数的名称.返回类型和参数.函数声明包括以下几个部分: ret ...

  8. python nums函数_Python函数

    一.简介 函数是可重用的程序代码块.函数的作用,不仅可以实现代码的复用,更能实现代码的一致性.一致性指的是,只要修改函数的代码,则所有调用该函数的地方都能得到体现. 函数用关键字def来定义,def关 ...

  9. Python源码学习:Python函数浅析-函数闭包

    Python源码分析 本文环境python2.5系列 参考书籍<<Python源码剖析>> 上一篇分析了函数参数的分析后,本文分析函数闭包的实现.函数闭包即函数定义和函数表达式 ...

最新文章

  1. js循环动态绑定带参数函数遇到的问题及解决方案[转]
  2. cic曲线是什么_贝塞尔曲线基本用法
  3. pandas使用iloc函数将dataframe的所有数据行反序(reverse the order of rows in dataframe)
  4. RecycleView 嵌套 RecycleView 导致自动滚动
  5. jquery 同级元素下的子元素_jq 获取所有父级元素及同级元素及子元素的方法(推荐)...
  6. MFC的静态库.lib、动态库.dll(包含引入库.lib)以及Unicode库示例
  7. 02.analyzer-tokenizer
  8. Nodejs之WebSocket
  9. 提高计算机水平的小技巧,五大电脑小技巧
  10. 利用微服务构建现代应用(一)
  11. spring cloud构建互联网分布式微服务云平台-Spring Cloud Commons 普通抽象
  12. 东线报接口 全网一手线报全网(京东,淘宝,天猫)最全优惠信息
  13. 论文中 一级标题、二级标题等 对应格式的统一修改
  14. 四旋翼飞行器5——各类方案设计及参考
  15. MTK MT6771处理器,helio P60芯片参考资料
  16. java异常处借接错书_Java入门第三季-异常-图书馆借书系统
  17. oppor9桌面布局设置_oppor9添加桌面图标
  18. 软文营销是什么,怎么理解
  19. Linux系统磁盘空间不足解决办法
  20. 洛谷P2327 [SCOI2005]扫雷【DP】【黄】

热门文章

  1. SMO写的查看数据库信息的代码
  2. c语言约瑟夫环问题,C++_详解约瑟夫环问题及其相关的C语言算法实现,约瑟夫环问题 N个人围成一圈 - phpStudy...
  3. spark抽取mysql数据到hive_使用spark将内存中的数据写入到hive表中
  4. 指令引用了 内存 该内存不能为read 一直弹窗_【翻译】使用Rust测试ARM和X86内存模型
  5. php数据库创建文件失败怎么回事,安装zblogPHP提示“创建c_option.php失败”解决方法...
  6. 微型计算机2017年9月上,2017年9月计算机一级考试WPS Office冲刺题
  7. java none怎么用tomcat_使用tomcat做java中间件
  8. azure git怎么使用_Azure(一)Azure Traffic Manager为我们的Web项目提供负载均衡
  9. android程序到处apk,导出已安装到手机中程序的apk文件
  10. μC/OS-Ⅱ 操作系统内核知识