linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数
接上一篇:linux_信号捕捉-signal函数-sigaction函数-sigaction结构体
今天来分享时序竞态的知识,关于时序竞态的问题,肯定会和cpu有关,也会学习两个函数,pause函数,sigsuspend函数, 也会分享什么是可重入函数和不可重入函数,话不多说,上一碗时序竞态的大菜:
此博主在CSDN发布的文章目录:【我的CSDN目录,作为博主在CSDN上发布的文章类型导读】
在介绍时序竞态之前,先介绍一下pause函数。
1.pause函数
函数作用:
调用该函数可以造成进程主动挂起,等待信号唤醒。调用该系统调用的进程将处于阻塞状态(主动放弃cpu) 直到有信号递达将其唤醒。
头文件:
#include <unistd.h>
函数原型:
int pause(void);
函数参数:
无
返回值:
返回值:-1 并设置errno为EINTR
① 如果信号的默认处理动作是终止进程,则进程终止,pause函数么有机会返回。
② 如果信号的默认处理动作是忽略,进程继续处于挂起状态,pause函数不返回。
③ 如果信号的处理动作是捕捉,则【调用完信号处理函数之后,pause返回-1】
errno设置为EINTR,表示“被信号中断”。想想我们还有哪个函数只有出错返回值。
④ pause收到的信号不能被屏蔽,如果被屏蔽,那么pause就不能被唤醒。
1.1.例子–pause函数运用:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void donothing(int signo)
{
}
unsigned int mysleep(unsigned int seconds)
{unsigned int ret;struct sigaction act, oldact;act.sa_handler = donothing;sigemptyset(&act.sa_mask);//信号集清零act.sa_flags = 0;
//注册信号捕捉函数sigaction(SIGALRM, &act, &oldact);alarm(seconds); //定时固定的秒数 1 pause(); //挂起ret = alarm(0); sigaction(SIGALRM, &oldact, NULL); //恢复SIGALRM 默认处理方式return ret;
}
int main(void)
{mysleep(5);return 0;
}
2.时序竞态
时序竞态: 由于进程之间执行的顺序不同,导致同一个进程多次运行后产生了不同结果的现象。
竞态问题总结:
竞态条件,跟系统负载有很紧密的关系,体现出信号的不可靠性。系统负载越严重,信号不可靠性越强。
不可靠由其实现原理所致。信号是通过软件方式实现(跟内核调度高度依赖,延时性强),每次系统调用结束后,或中断处理处理结束后,需通过扫描PCB中的未决信号集,来判断是否应处理某个信号。当系统负载过重时,会出现时序混乱。
这种意外情况只能在编写程序过程中,提早预见,主动规避,而无法通过gdb程序调试等其他手段弥补。且由于该错误不具规律性,后期捕捉和重现十分困难。
3.时序竞态问题1-信号处理
为什么会有时序竞态的问题产生,是因为cpu在执行进程的时候,一个进程只执行一个时间片段,所以,你写的程序运行的时候,有时候执行千次万次看似没什么问题,可是某一次突然就崩了,当你去查问题的时候,复查了很长的时间,都没有找到问题,这种问题的出现的概念可能是千万分之一,不容易发生,但一发生就是致命问题,而这种问题还不易发现,只能通过我们日常写代码的经验来避免。
例如在1.1的例子中,在调用alarm函数后,失去CPU,CPU去执行别的进程了,当执行别的进程的时间大于定时的时间后,会发生什么问题, 如下图。
就这样,本能定时1s的程序,成了永久阻塞了,这种情况,是可能发生的,而发生的几率,可能就是千万分之一。
设想在商业代码中出现这种错误,那后果则是毁灭性的。
当然,在上述案例中,也有解决方法,那就是利用信号的屏蔽机制来解决,这就得说一下另一个函数sigsuspend了。
3.1.解决时序问题1-sigsuspend函数
函数作用:
挂起等待信号。
头文件:
#include <signal.h>
函数原型:
int sigsuspend(const sigset_t *mask);
函数参数:
mask:调用该函数期间决定信号屏蔽字得集合
返回值:
错误返回-1,并设置errno以指示错误(通常为EINTR)。
EINTR:被一个信号中断。
可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑,但无论如何设置,程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应该使用sigsuspend替换pause。
原子操作:cpu在执行这个函数就会把他执行完,不会停止
3.2.例子-解决例1.1时序竞态问题1代码:
#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;/*为SIGALRM设置捕捉函数,一个空函数*/newact.sa_handler = sig_alrm;//将信号集清零sigemptyset(&newact.sa_mask);newact.sa_flags = 0;//注册信号捕捉函数,oldact保留原有的信号集sigaction(SIGALRM, &newact, &oldact);/*设置阻塞信号集,阻塞SIGALRM信号*/sigemptyset(&newmask);//将信号集清零sigaddset(&newmask, SIGALRM);//将SIGALRM信号加入信号集,置1//屏蔽SIGALRM信号,设置信号屏蔽字,oldmask保留原有的信号集sigprocmask(SIG_BLOCK, &newmask, &oldmask); //原子操作,即调用该函数期间不能失去cpu//定时nsecs秒,到时后可以产生SIGALRM信号alarm(nsecs);/*构造一个调用sigsuspend临时有效的阻塞信号集,* 在临时阻塞信号集里解除SIGALRM的阻塞*/suspmask = oldmask; //sigdelset(&suspmask, SIGALRM); //在suspmask集合中清除对SIGALRM函数的屏蔽/*sigsuspend调用期间,采用临时阻塞信号集suspmask替换原有阻塞信号集* 这个信号集中不包含SIGALRM信号,同时挂起等待,* 当sigsuspend被信号唤醒返回时,恢复原有的阻塞信号集*/sigsuspend(&suspmask); unslept = alarm(0);//恢复SIGALRM原有的处理动作,呼应前面注释1sigaction(SIGALRM, &oldact, NULL);//解除对SIGALRM的阻塞,呼应前面注释2sigprocmask(SIG_SETMASK, &oldmask, NULL);return(unslept);
}
int main(void)
{
while(1)
{mysleep(2);printf("Two seconds passed\n");}return 0;
}
4.时序竞态问题2-全局变量异步I/O
分析如下父子进程交替数数程序。
当捕捉函数里面的sleep取消,程序即会出现问题。
造成该问题出现得原因是什么呢?
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>int n = 0, flag = 0;
void sys_err(char *str)
{perror(str);exit(1);
}
void do_sig_child(int num)
{printf("I am child %d\t%d\n", getpid(), n);n += 2;flag = 1;sleep(1);
}
void do_sig_parent(int num)
{printf("I am parent %d\t%d\n", getpid(), n);n += 2;flag = 1;sleep(1);
}
int main(void)
{pid_t pid;
struct sigaction act;if ((pid = fork()) < 0)sys_err("fork");else if (pid > 0) { n = 1;sleep(1);act.sa_handler = do_sig_parent;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGUSR2, &act, NULL); //注册自己的信号捕捉函数 父使用SIGUSR2信号do_sig_parent(0); while (1) {/* wait for signal */;if (flag == 1) { //父进程数数完成kill(pid, SIGUSR1);flag = 0; //标志已经给子进程发送完信号}}} else if (pid == 0) { n = 2;act.sa_handler = do_sig_child;sigemptyset(&act.sa_mask);act.sa_flags = 0;sigaction(SIGUSR1, &act, NULL);while (1) {/* waiting for a signal */;if (flag == 1) {kill(getppid(), SIGUSR2);flag = 0;//分析,若是在cpu执行到此处时,收到父进程得信号,在flag还未被改完,就去执行do_sig_child该函数,会怎么样?}}}return 0;
}
示例中,通过flag变量标记程序实行进度。flag置1表示数数完成。flag置0表示给对方发送信号完成。
问题出现的位置,在父子进程kill函数之后需要紧接着调用 flag,将其置0,标记信号已经发送。但,在这期间很有可能被kernel调度,失去执行权利,而对方获取了执行时间,通过发送信号回调捕捉函数,从而修改了全局的flag。
如何解决该问题呢?
可以使用后续会分享到的“锁”机制。 当操作全局变量的时候,通过加锁、解锁来解决该问题。
现在,我们在编程期间如若使用全局变量,应在主观上注意全局变量的异步IO可能造成的问题。
5.时序竞态问题3-可/不可重入函数
一个函数在被调用执行期间(尚未调用结束),由于某种时序又被重复调用,称之为“重入”。根据函数实现的方法可分为“可重入函数”和“不可重入函数”两种。
可重入函数:函数内不能含有全局变量及static变量,不能使用malloc、free等。
不可重入函数:函数内含有全局变量及static变量,使用malloc、free,是标准I/O函数。
所以,我们的信号捕捉函数应该设计为可重入函数。
信号处理程序可以调用的可重入函数可参阅man 7 signal。
以上就是本次的分享了,希望能对广大网友有所帮助。
相关文章:

linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数
接上一篇:linux_信号捕捉-signal函数-sigaction函数-sigaction结构体 今天来分享时序竞态的知识,关于时序竞态的问题,肯定会和cpu有关,也会学习两个函数,pause函数,sigsuspend函数, 也会分享什么…...

Tomcat的负载均衡和动静分离
---------------------NginxTomcat负载均衡、动静分离------------------------- Nginx 服务器:192.168.80.10:80 Tomcat服务器1:192.168.80.100:80 Tomcat服务器2:192.168.80.101:8080 192.168.80.101:8081 1.部署Nginx 负载均衡器 system…...

C++每日一练:最长递增区间 阿波罗的魔力宝石 投篮
文章目录 前言一、最长递增区间二、阿波罗的魔力宝石三、投篮总结 前言 今天的题太简单,甚至 “最长递增区间” 和 “投篮” 就是一个问题。实在没事干,也给做了!直接上代码算了… 提示:以下是本篇文章正文内容 一、最长递增区间…...

HCIP之VLAN
目录 网络的三层架构 接入层 无线的缺陷: 上网用户数量增多,网络卡顿的原因 CSMA/CD --- 载波侦听多路访问/冲突检测 CSMA/CA --- 载波侦听多路访问/冲突避免 无线网络没有使用冲突检测技术的原因 汇聚层 连接两条线路的原因 核心层 VLAN VLAN配…...

1686_MATLAB处理Excel文件
全部学习汇总: GreyZhang/g_matlab: MATLAB once used to be my daily tool. After many years when I go back and read my old learning notes I felt maybe I still need it in the future. So, start this repo to keep some of my old learning notes servral …...

亿发软件:中大型仓库进出货管理系统解决方案,定制软件让仓储作业高效便捷
中大型仓库出入库管理是传统厂家供应链管理流程的重要部分,直接关乎货物在仓库当中存储的安全,和员工工作的效率。一旦仓库管理当中出现了疏漏,那么货物的信息数据就会发生变动,导致实际与账目不符。人工带来的低效与不可控是传统…...

SQL Server基础 第二章 表结构管理
目录 一、数据类型 1,字符类数据类型 2,数值型数据类型 3,日期/时间型数据类型 二、主键(Primary key) 三、默认值 四、唯一键(Unique) 五、自增标识 六、约束 七、外键 一、数据类型 …...

华为OD机试真题(Java),最小步骤数(100%通过+复盘思路)
一、题目描述 一个正整数数组 设为nums,最大为100个成员,求从第一个成员开始正好走到数组最后一个成员所使用的最小步骤数。 要求: 第一步 必须从第一元素起 且 1<第一步步长<len/2 (len为数组长度);从第二步开始只能以所…...

3分钟搞懂:JavaScript 和 ECMAScript
JavaScript 和 ECMAScript ECMAScript 是 JavaScript 语言的国际标准,JavaScript 是 ECMAScript 的一种实现(Adobe ActionScript 和 JScript 同样实现了 ECMAScript)。 ECMAScript 是欧洲计算机制造商协会 ECMA(European Comput…...

Bito:一款 iead/webstorm 神级插件,由 ChatGPT 团队开发,堪称辅助神器
前言: idea(后端),webstorm(前端)中可以用的一款辅助插件:Bito 个人尝试体验效果: 优点是:可以自动完成一些场景代码。 缺点:太慢了,大部分时间一直转圈 摘取文档: 什么是Bito&…...

[ 云原生 | Docker ] 构建高可用性的 SQL Server:Docker 容器下的主从同步实现指南
文章目录 一、前言二、SQL Server 主从同步的原理介绍三、具体的搭建过程3.1 准备工作3.1.1 卸载旧版本(如果有,可选,非必须)3.1.2 安装 Docker3.1.3 验证本地 Docker 是否安装成功 3.2 创建 Docker 网络3.3 创建主从节点的 SQL S…...

Binary Utilities非默认目录构建和安装
在AppArmor零知识学习六、源码构建(3)中,详细介绍了libapparmor的构建步骤,但那完全使用的是官网给出的默认参数。如果需要将目标文件生成到指定目录而非默认的/usr,则需要进行一些修改,本文就来详述如何进…...

【故障检测】基于 KPCA 的故障检测【T2 和 Q 统计指数的可视化】(Matlab代码实现)
💥 💥 💞 💞 欢迎来到本博客 ❤️ ❤️ 💥 💥 🏆 博主优势: 🌞 🌞 🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 …...

从“捐赠openEuler”到“向openEuler捐赠”,openEuler生态走入高速发展期
【中国,上海,2023年4月21日】openEuler Developer Day 2023于4月20-21日在线上和线下同步举办。本次大会由开放原子开源基金会指导,中国软件行业协会、openEuler社区、边缘计算产业联盟共同主办,以“万涓汇流,奔涌向前…...

ambari的kafka服务开启sasl
添加 sasl 配置⽂件 集群部署 Kafka2.2下载地址 http://archive.apache.org/dist/kafka/2.2.1/kafka_2.11-2.2.1.tgz 解压安装包 tar -zxvf kafka_2.11-2.2.1.tgz 部署略 ambari 数据kafka服务 在kafka的conf目录下创建sasl_conf目录,将kafka_client_jaas.conf/kafka_se…...

改善内部客户服务的 3 个技巧
在当今世界,许多公司都专注于改善客户关系管理,公司管理层面临的挑战是他们不仅拥有外部客户,员工也是有痛点和需求的内部客户。正如糟糕的客户服务会导致客户流失一样,糟糕的内部客户服务会增加员工流动率。在当今瞬息万变的就业…...

使用Apache POI的SXSSFworkbook实现大量数据导出到Excel文件
Apache POI是一个开源的、用来读写微软Excel文件的Java工具包,一般用来读取Excel文件中的数据或者将数据导出到Excel文件。HSSFWorkbook用来处理早期版本的Excel文件(xls格式),而XSSFWorkbook用来处理新版本Excel文(xl…...

【技术选型】Java 定时任务
文章目录 背景一、基础1.1 Cron表达式1.2 定时任务的三大组成部分 二、Java做定时任务的技术方案比较2.1、JDK seelp实现定时任务2.2、JDK Timer & TimerTask 实现定时任务2.3、JDK ScheduledExecutorService2.4、Quartz框架2.5、Spring Task 中的 schedule2.6、Elastic-Jo…...

让你立刻学会指针
☃️个人主页:fighting小泽 🌸作者简介:目前正在学习C语言和数据结构 🌼博客专栏:C语言学习 🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪&am…...

重塑元宇宙体验!元宇宙实时云渲染解决方案来了
元宇宙作为人工智能、云计算和数字孪生等前沿技术的结合体,近年来越发受到各大企业重视。 元宇宙的应用场景层出不穷,不仅包括营销推广场景,还有品牌活动和电商销售,能有效提升品宣和商业转化效果。 元宇宙也具有极大的建设价值…...

Node【Global全局对象】
文章目录 🌟前言🌟Global全局对象🌟Global对象属性与方法🌟Global对象属性🌟process🌟Buffer类🌟console 🌟写在最后 🌟前言 哈喽小伙伴们,新的专栏 Node 已…...

【技术】《Netty》从零开始学netty源码(四十一)之PoolChunk
PoolChunk 我们再回顾以下netty中与内存相关的类: 前面我们已经分析了PoolSubpag,本章我们分析PoolChunk,先看下它的属性值: 为了更好的理解这些属性值,我们结合它的构造函数来理解,具体的源码如下: 其…...

新建虚拟机更改ip(连接xshell)
# 查看网络设备 [rootcentos79 ~]# nmcli device DEVICE TYPE STATE CONNECTION ens32 ethernet 已连接 ens32 ens33 ethernet 已连接 ens33 virbr0 bridge 已连接 virbr0 lo loopback 未托管 -- # 查看…...

什么是VBST和PVST?两者有啥区别?
在计算机网络中,VLAN(Virtual Local Area Network,虚拟局域网)是一种将局域网划分为多个逻辑上独立的子网的技术,它可以帮助网络管理员更好地管理网络资源。 在VLAN技术中,STP(Spanning Tree P…...

记录-JavaScript常规加密技术
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 当今Web开发中,数据安全是一个至关重要的问题,为了确保数据的安全性,我们需要使用加密技术。JavaScript作为一种客户端编程语言,可以很好地为数据进行加…...

二十三、高级网络技术及应用——BFD解析
文章目录 前言一、BFD 简介1、概述:2、作用: 二、静态路由调用 BFD1、配置静态 BFD2、配置动态 BFD 三、OSPF联动BFD四、BFD 单臂回声(one arm echo) 前言 BFD:Bidirectional Forwarding Detection,双向转…...

大家经常说的java八股文到底是什么?让我来总结一下吧!
八股文问题集合 面试必看java八股文 问题正在收录中,累了休息一会,如果有需要请,先关注,这几天会更帖子,答案后续补上 文章目录 八股文问题集合问题正在收录中,累了休息一会,如果有需要请&#…...

C++备忘录模式实践:轻松实现撤销与恢复功能
目录标题 引言(Introduction)备忘录模式定义及核心概念(Memento Pattern Definition and Core Concepts)备忘录模式的定义(Definition of Memento pattern)备忘录模式的主要角色(Key roles in M…...

如何选择CDN加速平台?
现如今全球CDN市场规模逐年攀升,在2017年全球CDN市场规模约为75亿美元,到2021年增长到200亿美元左右。我国CDN行业同样保持高速发展,自2017年的135亿元增长到2022年的300亿元左右。但是国内的CDN市场规模仅为全球市场的15%-20%,海外CDN市场空间巨大。 接…...

其实苹果知道自己离不开中国制造,因此悄悄给自己留了后路
苹果在加速离开中国,不过从苹果的做法却又可以看到它其实很清醒地认识到无法离开中国制造,因此它在力推印度制造的时候,其实并没拼尽全力,深刻认识到印度制造和印度市场与中国的差距。 一、印度制造和印度市场与中国的差距 2022年…...