1、背景
最近学习了全局变量的异步IO问题,参考其他人的博客和视频,成就这篇。如果有理解问题的话,请大家指出。
2、全局变量的异步IO问题
全局变量的异步IO问题属于时序竞态问题中比较常见的一种。由于kernel的调度关系,涉及全局变量控制的程序逻辑跑出设计者预计之外的结果。如(主控程序和信号捕捉函数的用户处理函数)对同一个变量进行修改,由于kernel调度的缘故,执行顺序与预期的不一致,导致程序没达到设计目的。
接下去同样借助一个例子来说明。程序设计目的是,主程序和子程序交替数数。
2.1 父子进程交替数数
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
int n = 0, flag = 0; ;
//pid_t pid;
void sys_err(char *str)
{
perror(str);
exit(1);
}
void child_handle_signal(int num)
{
printf("I am child %d\t%d\n", getpid(), n);
n += 2;
flag = 1;
//sleep(1);
//kill(getppid( ) , SIGUSR2);
}
void parent_handle_signal(int num)
{
printf("I am parent %d\t%d\n", getpid(), n);
n += 2;
flag = 1;
//sleep(1);
//kill(pid , SIGUSR1);
}
int main(void)
{
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);
parent_handle_signal(0);
while(1) {
if(flag == 1)
{
kill(pid , SIGUSR1);
//--->由于kernel 调度失去CPU时间
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) {
if(flag == 1)
{
kill(getppid() , SIGUSR2);
//--->由于kernel 调度失去CPU时间
flag = 0;
}
;
}
}
return 0;
}
正如代码//--->由于kernel 调度失去CPU时间中指出的一样,由于调度失去CPU时间,没有按照设计修改全局变量flag。如父进程在//--->由于kernel 调度失去CPU时间 失去了CPU时间,而子进程获取CPU时间,执行完信号处理函数中的数数行为,又完成了主进程中的发送信号函数。那么在父进程再次获得CPU时,先执行了信号处理函数中的数数行为,在把上次中断的//--->由于kernel 调度失去CPU时间之后的语句执行完,程序就走样了。这样就造成时序竞态问题。
解决问题的方法:是在程序编辑过程中,就主动避免全局变量异步IO的问题。另一个方法就是加锁操作。