3

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

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

我知道什么时候fork()被调用,父进程克隆所有内容:寄存器、程序计数器等。但这怎么可能呢?子进程退出后,父进程的变量值不应该改变吗?是因为系统将所有内容(包括父进程的指针变量)都放入堆栈并在子进程终止时弹出它们?

4

2 回答 2

4

当一个进程被分叉时,新进程对于所有(?)意图和目的都是原始进程的副本,具有自己的虚拟地址空间,文件描述符等在一个相当简单的视图中,相同的内存地址实际上将指向不同的每个进程的物理内存地址 - 您可以有两个相同的指针指向完全​​不同的数据。

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

于 2013-03-09T20:49:30.930 回答
2

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

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

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

于 2013-03-09T20:51:36.060 回答