我试图了解fork()/ Linux Kernel如何处理全局变量。
给定代码:
#include<signal.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include <sys/types.h>
pid_t pid;
int counter = 2;
void handler1(int sig)
{
counter = counter - 1;
printf("%d", counter);
exit(0);
}
int main()
{
signal(SIGUSR1, handler1); //Install Handler
printf("%d", counter); //Print Parent global variable
pid = fork( ); //Fork(), child pid = 0, parent's pid = positive int.
if (pid == 0) //Parent skips this, child goes into infinite loop
{
while(1) {}; // simulate doing some work
}
kill(pid, SIGUSR1); //While child is the loop, parents calls to terminate the child.
//Child will stop the infinite loop, and will not proceed any
//Will it call handler1 ???
wait(NULL); //Wait for child to be ripped
//Will it call handler1 second time ???
counter = counter + 1; //This will surely increment global variable
printf("%d", counter);
exit(0);
}
输出为2123
在fork()和信号处理程序被调用之后,Unix / Linux内核如何处理全局变量?他们是否在儿童和儿童之间分享?父母?
我对此代码的另一个问题是kill()&amp; wait()将处理全局变量以及它们将使用的集合 - 父级或子级?他们会调用信号处理程序???
谢谢!
答案 0 :(得分:5)
孩子获得全局变量的独立副本。这两个副本不共享。
答案 1 :(得分:3)
fork
在当前状态下创建进程的副本。除了显式映射的共享内存资源(匿名共享映射,共享文件映射,sysv共享内存块和POSIX共享内存块)之外,不会共享任何内容。
您还应该知道,虽然新进程有自己的文件描述符表副本,但这些文件描述符引用内核中相同的“打开文件描述”。除其他外,他们共享当前的寻求职位。
有关详细信息,请参阅:
http://www.opengroup.org/onlinepubs/9699919799/functions/fork.html
答案 2 :(得分:3)
在fork()
之后,整个过程(包括所有全局变量)都是重复的。子项是父项的完全副本,但它具有不同的PID,不同的父项,并且fork()
返回0。
子进程中的信号处理程序将使用子进程的全局变量的独立副本。
您看到2
打印两次的原因是打印后没有刷新标准输出。这就是:
counter
等于2. printf("%d", counter);
,将"2"
放入stdout
输出缓冲区,但不刷新它。尚未显示任何输出。fork()
,它复制了该过程。现在有两个counter
变量副本,两者都设置为2.还有两个stdout
输出缓冲区实例,两个实例都包含字符串"2"
。尚未显示任何输出。SIGUSR1
发送给孩子,并阻止wait()
。handler1()
,将子进程的counter
副本减1,并将"1"
放入子进程的stdout
输出缓冲区(现在包含{{1} }})。"21"
,作为副作用冲洗exit(0)
。输出stdout
现在出现,由孩子写,孩子退出。"21"
在父进程中返回。父级将其wait()
的副本增加到3,然后将counter
输出到其"3"
输出缓冲区(现在包含stdout
)。"23"
,作为副作用冲洗exit(0)
。输出stdout
现在出现,父输出退出。如果您将"23"
放在fflush(stdout);
之前,则fork()
只会打印一次,输出将为2
。最好在调用"213"
之前刷新所有缓冲的输出流。