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

竞态条件(时序竞态):

pause 函数

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

返回值:
  1. 如果信号的默认处理动作是终止进程,则进程终止,pause 函数么有机会返回。
  2. 如果信号的默认处理动作是忽略,进程继续处于挂起状态,pause 函数不返回。
  3. 如果信号的处理动作是捕捉,则【调用完信号处理函数之后,pause 返回-1】 errno 设置为 EINTR,表示“被信号中断”。想想我们还有哪个函数只有出错返回值。
  4. pause 收到的信号不能被屏蔽如果被屏蔽,那么 pause 就不能被唤醒。
使用 pause 和 alarm 来实现 sleep 函数。
/** 模拟实现sleep*/
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<errno.h>
void catch_sigalrm(int signo)//捕捉函数 保证pause不会被杀死
{;   
}unsigned int mysleep(unsigned int seconds)
{int ret;struct sigaction act,oldact;act.sa_handler = catch_sigalrm;sigemptyset(&act.sa_mask);act.sa_flags = 0;ret = sigaction(SIGALRM,&act,&oldact);//注册捕捉函数    改变了SIGALRM信号的设置if(ret == -1){perror("sigaction error");exit(1);}       alarm(seconds);                                                                  ret =  pause();//主动挂起 等信号if(ret == -1 && errno == EINTR){printf("pause sucess\n");}       alarm(0);//将闹钟清零sigaction(SIGALRM,&oldact,NULL);//恢复SIGALRN信号旧有的处理方式return ret;
}
int main(void)
{while(1){mysleep(3);printf("-----------------\n");}return 0;
}        

时序竞态

欲睡觉,定闹钟 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。

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

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383235.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程---8(全局变量异步I/O,可重入函数)

全局变量异步 I/O 分析如下父子进程交替 数数 程序。当捕捉函数里面的 sleep 取消&#xff0c;程序即会出现问题。请分析原因。 #include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h>intn0,flag0; void sys_err(char* s…

http使用post上传文件时,请求头和主体信息总结

请求头必须配置如下行&#xff1a; Content-Type : multipart/form-data; boundary---12321 boundary---12321位文件的分界线 body如下&#xff1a; "-----12321\r\n" //分割文件时加-- "Content-Disposition: form-data; name\"…

iconv 文件编码转换

iconv 文件编码转换 http://qq164587043.blog.51cto.com/261469/63349 linux shell 配置文件中默认的字符集编码为UTF&#xff0d;8 。UTF&#xff0d;8是unicode的一种表达方式&#xff0c;gb2312是和unicode都是字符的编码方式&#xff0c;所以说gb2312跟utf&#xff0d;8的…

Linu系统编程---9(SIGCHLD 信号,信号传参,中断系统调用)

SIGCHLD 信号 SIGCHLD 的产生条件 子进程终止时子进程接收到 SIGSTOP 信号停止时子进程处在停止态&#xff0c;接受到 SIGCONT 后唤醒时 借助 SIGCHLD 信号回收子进程 子进程结束运行&#xff0c;其父进程会收到 SIGCHLD 信号。该信号的默认处理动作是忽略。可以捕捉该信号…

Linu系统编程---10(Linux的终端,线路规程,网络终端,进程组)

终端 输入输出设备的总称 在 UNIX 系统中&#xff0c;用户通过终端登录系统后得到一个 Shell 进程&#xff0c;这个终端成为 Shell 进程的控制终端&#xff08;Controlling Terminal&#xff09;&#xff0c; 进程中&#xff0c;控制终端是保存在 PCB 中的信息&#xff0c;而 …

PCRE函数简介和使用示例

PCRE是一个NFA正则引擎&#xff0c;不然不能提供完全与Perl一致的正则语法功能。但它同时也实现了DFA&#xff0c;只是满足数学意义上的正则。 PCRE提供了19个接口函数&#xff0c;为了简单介绍&#xff0c;使用PCRE内带的测试程序(pcretest.c)示例用法。 1. pcre_compile 原型…

Linux系统编程---11(会话,守护进程,创建守护进程)

会话 创建会话 创建一个会话需要注意以下6点注意事项 调用进程不能是进程组组长&#xff0c;该进程变成新会话首进程该进程成为一个新进程组的组长进程需要root权限&#xff08;nbuntu不需要&#xff09;新会话丢弃原有的控制终端&#xff0c;该会话没有控制终端该调用进程是…

判断一段文件是UTF-8编码还是GB2312的编码方式

分类&#xff1a; 算法 cpp2012-03-10 16:01 7120人阅读 评论(2) 收藏 举报null生活c对于只包含中文和英文的文本中判断编码方式是非常简单的&#xff0c;中文的编码方式最常用的是GBK&#xff0c;字符集更大的如GBK向下兼容GB2312&#xff0c;其中包含的的很多一部分字符是我们…

判断文件的编码方式

/*功能&#xff1a;实现文件编码格式的判断通过一个文件的最前面三个字节&#xff0c;可以判断出该的编码类型&#xff1a;ANSI&#xff1a;        无格式定义&#xff1b;(第一个字节开始就是文件内容)Unicode&#xff1a;       前两个字节为FFFE&#xff1b;…

Linux系统编程----12(线程概念,Linux线程实现原理,栈中ebp指针和ebp指针,线程的优缺点和共享资源)

线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列” 一切进程至少都有一个执行线程线程在进程内部运行&#xff0c;本质是在进程地址空间内运行在Linux系统中&#xff0…

Linux系统编程---13(线程控制函数,创建线程,循环创建多个线程,线程间共享全局变量)

线程控制 操作系统并没有提供创建线程的系统调用接口&#xff0c;因此大佬们封装了一个线程的接口库实现线程控制。意为着用户创建线程都使用的是库函数&#xff08;所以有时候我们说创建的线程是一个用户态线程&#xff0c;但是在内核中对应有一个轻量级进程实现线程程序的调…

Linux系统编程---14(回收子线程,回收多个子线程,线程分离,杀死线程)

回收子线程 pthread_join 函数 阻塞等待线程退出&#xff0c;获取线程退出状态 其作用&#xff0c;对应进程中 waitpid() 函数。 int pthread_join (pthread_t thread,void** retval); 成功&#xff1a;0&#xff0c;失败&#xff1a;错误号 参数&#xff1a;thread&#x…

Linux系统编程----15(线程与进程函数之间的对比,线程属性及其函数,线程属性控制流程,线程使用注意事项,线程库)

对比 进程 线程 fork pthread_create exit (10) pthread_exit &#xff08;void *&#xff09; wait (int *) pthread_join &#xff08;&#xff0c;void **&#xff09;阻塞 kill pthread_cancel ();必须到取消点&#xff08;检查点&#xff09;&#xff1a;…

内核双向循环链表

#include <string.h>#include <stdio.h>#include <stdlib.h>#include<malloc.h>#include <arpa/inet.h>//链表头结构struct list_head{struct list_head *next,*prev;};//真正实现链表插入操作void _list_add(struct list_head *nnew,struct lis…

Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

同步概念 所谓同步&#xff0c;即同时起步&#xff0c;协调一致。不同的对象&#xff0c;对“同步”的理解方式略有不同。如&#xff0c;设备同步&#xff0c;是指在两 个设备之间规定一个共同的时间参考&#xff1b;数据库同步&#xff0c;是指让两个或多个数据库内容保持一致…

转移字符的转换

使得网页上不会显示 \x0a\x0a \x0a \x0a \x0a \x0a 类似的字符static int te_escape_isDec(char *ptr, unsigned int len) { …

Linux系统编程---17(条件变量及其函数,生产者消费者条件变量模型,生产者与消费者模型(线程安全队列),条件变量优点,信号量及其主要函数,信号量与条件变量的区别,)

条件变量 条件变量本身不是锁&#xff01;但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。 主要应用函数&#xff1a; pthread_cond_init 函数pthread_cond_destroy 函数pthread_cond_wait 函数pthread_cond_timedwait 函数pthread_cond_signa…

好友

http://blog.csdn.net/liangyuannao/article/details/8583139

Linux系统编程---18(线程池相关概念及其实现)

线程池 概念&#xff1a; 一堆线程任务队列 作用 避免大量线程频繁的创建/销毁时间成本避免瞬间大量线程创建耗尽资源&#xff0c;程序崩溃危险 实现 创建固定数量的线程创建一个线程安全的任务队列 一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓…

设计模式--1(设计模式基础,设计模式基本原则,设计模式分类)

设计模式基础 模式 在一定环境中解决某一问题的方案&#xff0c;包括三个基本元素–问题&#xff0c;解决方案和环境。大白话&#xff1a;在一定环境下&#xff0c;用固定套路解决问题。 设计模式 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使…