总部基地网站建设公司,seo优化技术培训中心,wordpress 下载短代码,阿里万网站建设竞态条件(时序竞态)#xff1a;
pause 函数
调用该函数可以造成进程主动挂起#xff0c;等待信号唤醒。调用该系统调用的进程将处于阻塞状态(主动放弃 cpu) 直 到有信号递达将其唤醒#xff0c;等不到一直等 int pause(void); 返回值#xff1a;-1 并设置 errno 为 EINTR…竞态条件(时序竞态)
pause 函数
调用该函数可以造成进程主动挂起等待信号唤醒。调用该系统调用的进程将处于阻塞状态(主动放弃 cpu) 直 到有信号递达将其唤醒等不到一直等 int pause(void); 返回值-1 并设置 errno 为 EINTR
返回值
如果信号的默认处理动作是终止进程则进程终止pause 函数么有机会返回。如果信号的默认处理动作是忽略进程继续处于挂起状态pause 函数不返回。如果信号的处理动作是捕捉则【调用完信号处理函数之后pause 返回-1】 errno 设置为 EINTR表示“被信号中断”。想想我们还有哪个函数只有出错返回值。pause 收到的信号不能被屏蔽如果被屏蔽那么 pause 就不能被唤醒。
使用 pause 和 alarm 来实现 sleep 函数。
/** 模拟实现sleep*/
#includestdio.h
#includeunistd.h
#includestdlib.h
#includesignal.h
#includeerrno.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 函数。设想如下时序
注册 SIGALRM 信号处理函数 sigaction…) 2调用 alarm(1) 函数设定闹钟 1 秒。函数调用刚结束开始倒计时 1 秒。当前进程失去 cpu内核调度优先级高的进程(有多个)取代当前进程。 当前进程无法获得 cpu进入就绪态等待 cpu。1 秒后闹钟超时内核向当前进程发送 SIGALRM 信号(自然定时法与进程状态无关)高优先级进程尚未 执行完当前进程仍处于就绪态信号无法处理(未决)优先级高的进程执行完当前进程获得 cpu 资源内核调度回当前进程执行。SIGALRM 信号递达信号设置 捕捉执行处理函数 sig_alarm。信号处理函数执行结束返回当前进程主控流程 pause()被调用挂起等待。 欲等待alarm函数发送的SIGALRM 信号将自己唤醒SIGALRM 信号已经处理完毕pause 不会等到。
如何解决时序问题重点
可以通过设置屏蔽 SIGALRM 的方法来控制程序执行逻辑但无论如何设置程序都有可能在“解除信号屏蔽” 与“挂起等待信号”这个两个操作间隙失去 cpu 资源。除非将这两步骤合并成一个“原子操作”。sigsuspend 函数具 备这个功能。在对时序要求严格的场合下都应该使用 sigsuspend 替换 pause。
int sigsuspend(const sigset_t* mask); 挂起等待信号。 sigsuspend 函数调用期间进程信号屏蔽字由其参数 mask 指定。 可将某个信号如 SIGALRM从临时信号屏蔽字 mask 中删除这样在调用 sigsuspend 时将解除对该信号的屏 蔽然后挂起等待 当sigsuspend返回时进程的信号屏蔽字恢复为原来的值。 如果原来对该信号是屏蔽态 sigsuspend 函数返回后仍然屏蔽该信号。
总结
竞态条件跟系统负载有很紧密的关系体现出信号的不可靠性。系统负载越严重信号不可靠性越强。不可靠由其实现原理所致**。信号是通过软件方式实现(跟内核调度高度依赖延时性强)每次系统调用结束后 或中断处理处理结束后需通过扫描 PCB 中的未决信号集来判断是否应处理某个信号。**当系统负载过重时会出 现时序混乱。这种意外情况只能在编写程序过程中提早预见主动规避而无法通过 gdb 程序调试等其他手段弥补。且由 于该错误不具规律性后期捕捉和重现十分困难