【问题标题】:How come forked processes do not affect each other when there is a global pointer?当有全局指针时,为什么分叉的进程不会相互影响?
【发布时间】:2013-03-09 20:20:46
【问题描述】:

我知道fork() 函数创建了一个与其父进程相同的进程,只是它的 PID 不同。它们最初具有相同的变量,对这些变量所做的更改不会相互影响。但是当一个全局指针变量被共享时会发生什么?

我已经编写了一些代码并打印了结果。似乎父进程和子进程都有指向相同内存位置的指针,但是对这些内存位置所做的更改,即父进程中的*p = 1和子进程中的*p = 2,不会影响彼此。另请注意,我将父进程设为wait(NULL),直到子进程退出。所以子进程改变了与父进程指针内存地址相同的指针所指向的值。

我知道当fork() 被调用时,父进程会克隆所有内容:寄存器、程序计数器等。但这怎么可能呢?子进程退出后,父进程的变量值不应该改变吗?是不是因为系统把所有的东西(包括父进程的指针变量)都放到了栈上,当子进程终止时弹出?

【问题讨论】:

  • 每个进程都有自己的虚拟内存映射——地址是“假装”的。
  • 阅读一些关于 Unix 或 Linux 编程的好书,例如 advancedlinuxprogramming.com 并了解更多关于 en.wikipedia.org/wiki/Virtual_memory 和例如mmap(2)fork(2)execve(2) 系统调用。
  • "我知道什么时候调用 fork(),进程共享所有内容,注册程序计数器等。" --- 当心,你知道一些不真实的事情。
  • “它(fork)创建了原始进程的完全相同的副本,包括所有文件描述符、寄存器——一切。” Andrew Tannenbaum - 操作系统设计和实现。通过“分享”,我实际上试图表示克隆,如果这就是你所说的,我知道一些不正确的事情。它们不“共享”,它们被“克隆”到子处理器。这就是我的意思。
  • @Volkanİlbeyli 对。这是一个副本。它没有共享。

标签: c linux pointers global-variables fork


【解决方案1】:

当一个进程被分叉时,新进程是所有(?)意图和目的的原始进程的副本,具有自己的virtual address space,文件描述符等。在一个相当简单的视图中,相同的内存地址实际上会为每个进程指向不同的物理内存地址——你可以有两个相同的指针指向完全​​不同的数据。

自然,在现代操作系统中,事情并不那么简单。例如,fork() 实际上并没有复制所有内容,因为这会浪费处理器时间和内存。内核利用一点page table 操作来实现copy-on-write 内存复制。此外,出于性能和正确性的原因,可以在一定程度上控制哪些资源将实际克隆到子进程。

【讨论】:

    【解决方案2】:

    这是一个很大的话题,但这里有一个简短的解释。您可能将执行线程与分叉进程混淆了。在 Unix 系统中,每个进程都是独立的,并且有自己的虚拟地址空间。这意味着将指针设置为相同地址的两个进程实际上通常会在物理内存中使用不同的地址。这个概念是任何体面操作系统的重要组成部分——在更原始的操作系统上,正在运行的程序将可以直接访问物理内存。事实上,如果您一次运行一千个可执行文件实例,您可能会发现每个实例都使用完全相同的地址。

    除了安全方面的好处外,它还允许程序的“文本”部分(二进制指令)由正在运行的程序的所有实例共享。内核可以将每个进程映射到物理内存中的相同地址。

    孩子不完全是父母的副本,或者说是共享一切。有一长串继承的东西,以及没有的东西。它几乎是相同的 - 它具有相同的可执行代码、相同的打开文件等,但它是一个完全独立的独立进程。

    【讨论】:

    • 老实说,我还没有了解线程,所以我不会混淆它们:) +1 为你提供了很好的、通知性的答案,但另一个答案是我正在寻找的,所以我接受了。
    猜你喜欢
    • 2015-11-26
    • 1970-01-01
    • 2021-04-08
    • 2021-06-24
    • 2020-09-01
    • 2011-01-24
    • 2011-05-10
    • 2021-10-18
    • 1970-01-01
    相关资源
    最近更新 更多