分叉、信号以及它们如何与 C 中的全局变量交互
我试图了解 fork()/Linux 内核如何处理全局变量。
给定代码:
#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() & wait() 将处理全局变量以及它们将使用什么集合 - 父母的还是孩子的?他们会调用信号处理程序吗???
谢谢 !
I am trying to understand how fork()/Linux Kernel deals with global variables.
Given code:
#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);
}
The output is 2123
How does Unix/Linux kernel deals with global variables after fork() and signal handlers are called ??? Do they get shared between child & parent ?
Another issues I have with this code, is how kill() & wait() will deal with global variables and what set will they use - parent's or child's ?? And will they call signal handler ???
Thanks !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
子级获得全局变量的独立副本。这两个副本不共享。
The child gets an independent copy of the global variables. The two copies are not shared.
在
fork()
之后,整个过程,包括所有全局变量,都会被重复。子级是父级的精确副本,只不过它有不同的 PID、不同的父级,并且fork()
返回 0。子级中的信号处理程序将使用子级的全局变量的独立副本。
您看到
2
打印两次的原因是您在打印后没有刷新标准输出。发生的情况如下:counter
等于 2。printf("%d", counter);
,这会将"2"
进入stdout
输出缓冲区,但不刷新它。尚未出现任何输出。fork()
,这会重复该过程。现在有两个counter
变量的副本,并且都设置为 2。还有两个stdout
输出缓冲区的实例,它们都包含字符串“2”
。尚未出现任何输出。SIGUSR1
,并在wait()
上阻塞。handler1()
,将子进程的counter
副本减为 1,并将"1"
放入子进程的stdout
输出缓冲区(现在包含“21”
)。exit(0)
,其副作用是刷新stdout
。现在出现输出"21"
,由子进程写入,然后子进程退出。wait()
在父进程中返回。父级将其counter
副本增加到 3,然后将"3"
打印到其stdout
输出缓冲区(现在包含" 23"
)。exit(0)
,其副作用是刷新stdout
。现在出现输出"23"
,并且父进程退出。如果将
fflush(stdout);
放在fork()
之前,则2
只会打印一次,输出将为“213”
。在调用 fork() 之前刷新所有缓冲的输出流是一个很好的做法。After
fork()
, the entire process, including all global variables, is duplicated. The child is an exact replica of the parent, except that it has a different PID, a different parent, andfork()
returned 0.A signal handler in the child will use the child's independent copy of the global variable.
The reason you're seeing
2
printed twice is that you haven't flushed standard output after printing it. This is what happens:counter
is equal to 2.printf("%d", counter);
, which puts"2"
into thestdout
output buffer, but does not flush it. No output appears yet.fork()
is called, which duplicates the process. There are now two copies of thecounter
variable, and both are set to 2. There are also two instances of thestdout
output buffer, both of which contain the string"2"
. No output appears yet.SIGUSR1
to the child, and blocks onwait()
.handler1()
, which decrements the child's copy ofcounter
to 1, and puts"1"
into the child'sstdout
output buffer (which now contains"21"
).exit(0)
, which as a side-effect flushesstdout
. The output"21"
appears now, written by the child, and the child exits.wait()
returns in the parent process. The parent increments its copy ofcounter
to 3, and then prints"3"
into itsstdout
output buffer (which now contains"23"
).exit(0)
, which as a side-effect flushesstdout
. The output"23"
appears now, and the parent exits.If you put
fflush(stdout);
before thefork()
, the2
will only be printed once, and the output will be"213"
. It is good practice to flush all buffered output streams before callingfork()
.fork
创建进程当前状态的副本。除了显式映射的共享内存资源(匿名共享映射、共享文件映射、sysv 共享内存块和 POSIX 共享内存块)之外,不共享任何内容。您还应该注意,虽然新进程有自己的文件描述符表副本,但这些文件描述符引用内核中相同的“打开文件描述”。除其他外,它们共享当前的搜索位置。
有关更多详细信息,请参阅:
http://www.opengroup.org/onlinepubs/9699919799 /functions/fork.html
fork
creates a copy of the process in its current state. Nothing is shared except explicitly-mapped shared memory resources (anonymous shared maps, shared file maps, sysv shared memory blocks, and POSIX shared memory blocks).You should also be aware that while the new process has its own copy of the file descriptor table, these file descriptors refer to the same "open file descriptions" in the kernel. They share a current seek position, among other things.
For further details, see:
http://www.opengroup.org/onlinepubs/9699919799/functions/fork.html