分叉、信号以及它们如何与 C 中的全局变量交互

发布于 2024-10-08 15:11:41 字数 1365 浏览 2 评论 0原文

我试图了解 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赠我空喜 2024-10-15 15:11:41

子级获得全局变量的独立副本。这两个副本不共享

The child gets an independent copy of the global variables. The two copies are not shared.

望喜 2024-10-15 15:11:41

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, and fork() 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.
  • Parent process executes printf("%d", counter);, which puts "2" into the stdout output buffer, but does not flush it. No output appears yet.
  • fork() is called, which duplicates the process. There are now two copies of the counter variable, and both are set to 2. There are also two instances of the stdout output buffer, both of which contain the string "2". No output appears yet.
  • The parent sends SIGUSR1 to the child, and blocks on wait().
  • The child executes handler1(), which decrements the child's copy of counter to 1, and puts "1" into the child's stdout output buffer (which now contains "21").
  • The child executes exit(0), which as a side-effect flushes stdout. The output "21" appears now, written by the child, and the child exits.
  • wait() returns in the parent process. The parent increments its copy of counter to 3, and then prints "3" into its stdout output buffer (which now contains "23").
  • The parent executes exit(0), which as a side-effect flushes stdout. The output "23" appears now, and the parent exits.

If you put fflush(stdout); before the fork(), the 2 will only be printed once, and the output will be "213". It is good practice to flush all buffered output streams before calling fork().

╄→承喏 2024-10-15 15:11:41

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文