【问题标题】:confusing fork system call令人困惑的 fork 系统调用
【发布时间】:2010-03-25 04:20:22
【问题描述】:

我只是检查 fork 系统调用的行为,我发现它非常混乱。 我在一个网站上看到

Unix 将复制父地址空间的精确副本并将其提供给子地址。因此,父子进程有独立的地址空间

#include <stdio.h>
#include <sys/types.h>

int main(void)
{
pid_t pid;
char y='Y';
char *ptr;
ptr=&y;
pid = fork();
if (pid == 0)
{
y='Z';
printf(" *** Child process  ***\n");
printf(" Address  is %p\n",ptr);
printf(" char value is %c\n",y);
sleep(5);
}
else
{
sleep(5);
printf("\n ***parent process ***\n",&y);
printf(" Address  is %p\n",ptr);
printf(" char value is %c\n",y);
}
}

上述程序的输出是:

 *** Child process  ***
 Address  is 69002894
 char value is Z

 ***parent process ***
 Address  is 69002894
 char value is Y

所以从上面提到的语句看来,子进程和父进程似乎有单独的地址空间。这就是为什么单独打印 char 值以及为什么我在子进程和父进程中看到变量的地址相同的原因。?

请帮助我理解这一点!

【问题讨论】:

  • 变量名称仅在某些特定语言的编译时存在。在运行时,您的代码使用精确地址(对于堆栈,它使用某个寄存器的偏移量,并且在程序映射到内存后内存指针被重新定位)。同样,正如您的示例所述 - 就在分叉当前进程之前,您将指针存储在某个地方(它甚至可以是一些外部存储)。因此,如果 fork() 会导致内存布局发生变化 - 从该系统调用返回后,您的程序将无法进一步工作。
  • 答案是正确的,但在您的实际示例中,还有另一个问题。您将 Y 的地址存储在分叉之前的 ptr 中,因此 ptr 包含“69002894”。在 fork 之后, ptr 仍然会在父进程和子进程中包含该值,即使 Y 的地址在两个进程之一中会发生变化。为了正确起见,您必须在 printf 语句中打印 &Y。
  • @laurent 在 fork ptr 之后也将被复制到子进程。这意味着孩子和父母将有两个不同的ptr。请按照您自己在 printf 中的建议更改语句进行检查。您将得到相同的结果。
  • 是的,由于答案中提到的原因(虚拟地址空间),我知道您会得到相同的结果。我的意思是,IF y 的地址在孩子的进程中会有所不同(每个人都同意不是这种情况),PTR 的值仍然是 Y 的地址父进程而不是子进程中 Y 的地址。所以你不会在你的 printfs 中看到差异。

标签: c++ c unix fork


【解决方案1】:

基本上,虚拟内存的概念将进程视为系统的唯一所有者。它感觉它可以访问完整的内存。

但实际上,操作系统只给了它一个虚拟内存,由操作系统通过MMU映射到实际内存。

因此,在您的情况下,每个进程(父进程和子进程)都有自己的地址空间。这对两者都是分开的。现在在这里,地址空间是指虚拟地址空间。

因此,尽管在父子节点中存在相同的地址,但这只是虚拟地址。并且每个映射到不同的物理地址。

希望对你有帮助!!

【讨论】:

    【解决方案2】:

    你是对的。只要您调用fork(),就会存在两个相同的进程。所以y的地址对于每个进程中y的副本来说都是一样的。两个进程之间的唯一区别是,一个fork() 返回0,另一个返回子进程的PID。您的程序正在使用该信息在父母和孩子中执行不同的行为,因此您可以获得适当的输出。

    在“现实生活”中,操作系统做了很多优化以使fork() 真的快。这意味着实际的物理行为可能不涉及内存空间的完整副本。但是,从逻辑上讲,您可以这样对待它。

    【讨论】:

    • 但是“孩子和父母的地址空间分开”的评论呢?
    • @benjamin,是的,它们是不同的进程,所以每个都有自己独立的虚拟内存空间。一旦fork() 返回,它们就完全独立了。
    • “单独的地址空间”意味着一个进程中的给定地址指的是另一个进程中相同地址的单独内存位。这就是您示例中的地址 69002894 能够同时存储 XY 的方式 - “进程 A 中的地址 69002894”与“进程 B 中的地址 69002894”不同。
    【解决方案3】:

    它们有独立的地址空间——这正是为什么允许相同的内存地址具有不同值的原因。内存地址只在进程的上下文中才有意义。

    【讨论】:

      【解决方案4】:

      地址 221 P Street 是独立于地址 221 C Street 的建筑物。即使地址号相同,它们的内容也不同。

      【讨论】:

        【解决方案5】:

        您必须将 pid 替换为 ptr 。 要获取父子 ID,您必须在 printf(" Address is %p\n",pid); 中使用 pid 而不是 ptr。在fork() 程序运行后分为两部分。一个是孩子,另一个是父母。如果你从 fork() 之前使用的变量中调用地址,你将得到相同的结果,无论是父母还是孩子。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-04-27
          • 2022-01-21
          • 2022-01-17
          • 2018-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-11
          相关资源
          最近更新 更多