Linux系统编程—-8(竞态条件,时序竞态,pause函数,如何解决时序竞态)

竞态条件(时序竞态):

pause 函数

调用该函数可以造成进程主动挂起,等待信 唤醒。调用该系统调用的进程将处于阻塞状态(主动放弃 cpu) 直 到有信 递达将其唤醒,等不到一直等
返回值:-1 并设置 errno 为 EINTR

返回值:
  1. 如果信 的默认处理动作是终止进程,则进程终止,pause 函数么有机会返回。
  2. 如果信 的默认处理动作是忽略,进程继续处于挂起状态,pause 函数不返回。
  3. 如果信 的处理动作是捕捉,则【调用完信 处理函数之后,pause 返回-1】 errno 设置为 EINTR,表示“被信 中断”。想想我们还有哪个函数只有出错返回值。
  4. pause 收到的信 不能被屏蔽如果被屏蔽,那么 pause 就不能被唤醒。
使用 pause 和 alarm 来实现 sleep 函数。

时序竞态

欲睡觉,定闹钟 10 分钟,希望 10 分钟后闹铃将自己唤醒。 正常:定时,睡觉,10 分钟后被闹钟唤醒。
异常:闹钟定好后,被唤走,外出劳动,20 分钟后劳动结束。回来继续睡觉计划,但劳动期间闹钟已经响过, 不会再将我唤醒。

时序问题分析

借助 pause 和 alarm 实现的 mysleep 函数。设想如下时序:

  1. 注册 SIGALRM 信 处理函数 (sigaction…) 2
  2. 调用 alarm(1) 函数设定闹钟 1 秒。
  3. 函数调用刚结束,开始倒计时 1 秒。当前进程失去 cpu,内核调度优先级高的进程(有多个)取代当前进程。 当前进程无法获得 cpu,进入就绪态等待 cpu。
  4. 1 秒后,闹钟超时,内核向当前进程发送 SIGALRM 信 (自然定时法,与进程状态无关),高优先级进程尚未 执行完,当前进程仍处于就绪态,信 无法处理(未决)
  5. 优先级高的进程执行完,当前进程获得 cpu 资源,内核调度回当前进程执行。SIGALRM 信 递达,信 设置 捕捉,执行处理函数 sig_alarm。
  6. 信 处理函数执行结束,返回当前进程主控流程, pause()被调用挂起等待。 (欲等待alarm函数发送的SIGALRM 信 将自己唤醒)
  7. SIGALRM 信 已经处理完毕,pause 不会等到。

如何解决时序问题(重点)

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

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

总结

  1. 竞态条件,跟系统负载有很紧密的关系,体现出信 的不可靠性。系统负载越严重,信 不可靠性越强。
  2. 不可靠由其实现原理所致**。信 是通过软件方式实现(跟内核调度高度依赖,延时性强),每次系统调用结束后, 或中断处理处理结束后,需通过扫描 PCB 中的未决信 集,来判断是否应处理某个信 。**当系统负载过重时,会出 现时序混乱。
  3. 这种意外情况只能在编写程序过程中,提早预见,主动规避,而无法通过 gdb 程序调试等其他手段弥补。且由 于该错误不具规律性,后期捕捉和重现十分困难

文章知识点与官方知识档案匹配,可进一步学习相关知识CS入门技能树Linux入门初识Linux24898 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年7月15日
下一篇 2019年7月16日

相关推荐