C++ 为什么fork()使用相同的变量但值不同?

C++ 为什么fork()使用相同的变量但值不同?,c++,c++11,fork,C++,C++11,Fork,代码如下: #include <stdio.h> #include <unistd.h> void f(int&); void g(int&);

代码如下:

#include <stdio.h>                                                                                                                                                            
#include <unistd.h>

void f(int&);
void g(int&);

int main(int argc, char **argv)
{
    printf("--beginning of program\n");

    int counter = 0;
    pid_t pid = fork();
    if (pid == 0) {
        f(counter);
        printf("child process: %d, %p", counter, &counter);
    } else if (pid>0) {
        g(counter);
        for (int i=0; i<5; ++i) {
            sleep(1);
            printf("parent process: %d, %p\n", counter, &counter);
        }
    }
    printf("--end of program--\n");
    return 0;
}

void f(int& counter) {
    counter = 1;
    printf("in f: %d, %p-\n", counter, &counter);
}
void g(int& counter){
} 
显然,在子进程中,它是具有相同地址的相同参数,但值不同


为什么会发生这种情况?

每个进程都有自己的虚拟内存空间。

这意味着一个进程中的
0x7ffc9b01c6a4
与另一个进程中的
0x7ffc9b01c6a4
完全无关


这不是同一个对象;这是新流程中的一个对象。由于第二个进程是从第一个进程派生出来的,本质上是克隆进程,因此第二个进程中的对象应该与第一个进程中的对象存在于同一虚拟内存位置也就不足为奇了。

这是
fork()
的基础,这正是它能够工作的原因。要理解这一点,您需要记住,现代操作系统中进程的所有地址空间都是虚拟的——这意味着,它与实际的物理内存地址无关。访问地址为0x8000的内存(如果我记得地址正确的话)直接进入视频内存的日子一去不复返了。我曾经用这种方式编程,而不是屏幕操作例程,只是在视频内存中写入值,这要快得多。这很有趣:)

但它已经不复存在了。现在在用户程序中,地址与物理内存无关,只要您在“0x1234567”位置访问内存,就会进行转换。CPU知道如何将这个虚拟地址映射到物理内存地址,但没有人知道


因此,当您分叉进程时,会生成一个精确的内存副本。它具有相同的虚拟地址(因为内存副本是精确的!)。但由于这是一个不同的进程,CPU将把这些虚拟地址转换成不同的物理内存地址。至少,这是语义学。在真正的现代系统中,精确的内存复制不会真正发生-或者
fork()
会花费太长时间。相反,内存被标记为“写入时复制”。这意味着在修改数据之前,两个进程将访问相同的物理内存。但是一旦任何进程修改了内存,它就会被复制,现在每个人都有自己的副本

当你错的时候,尽量避免使用“清楚”这样的术语;)关于奶牛的观点很好。当然,即使在复制之后,地址仍然是相同的:)@LightnessRacesinOrbit,虚拟地址当然是相同的。OP看到的地址是的。
--beginning of program
in f: 1, 0x7ffc9b01c6a4-
child process: 1, 0x7ffc9b01c6a4--end of program--
parent process: 0, 0x7ffc9b01c6a4
parent process: 0, 0x7ffc9b01c6a4
parent process: 0, 0x7ffc9b01c6a4
parent process: 0, 0x7ffc9b01c6a4
parent process: 0, 0x7ffc9b01c6a4
--end of program--