2个精确的(易失性标记的)指针如何可以指向不同的值?分叉进程

发布于 2025-01-11 13:03:22 字数 2015 浏览 0 评论 0原文

目标

了解代码中发生的情况以及我错误的结论/错误的预测。

上下文

在尝试 fork 函数(并阅读我可能误解的文章)时,我得出结论,子级使用的数据是父级数据的副本。

  1. 为了使子进程与其父进程处理相同的数据,我创建了指针 p,假设分叉后其值在所有(两个)进程中都相同。
  2. 我通过打印孩子和父母存储的值来确保孩子和父母的指针都指向相同的内存空间。让我震惊的是,它们似乎也相同/完全相同——具有相同的地址。
    两个精确指针应该指向不同的值吗?在我的代码中他们做到了。
  3. 接下来,为了确保编译器不会执行任何优化,我将p指针标记为易失性
    但这并没有改变任何事情。这是代码。

一般代码

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


int main(){
  volatile int *volatile p= malloc(sizeof(int));
  *p= 6;
  

  if (fork()){ //Parent
    *p= 200; //Parent changes the value in "shared" memory

    printf("Parent: %p : %p : %i\n", &p, p, *p);
    wait(NULL);
  }else{ //Child
    sleep(3); //Child sleeps when parent is setting the "shared" value.

    printf("Child:  %p : %p : %i\n", &p, p, *p); //Child should read the same value.
  }
}

输出:

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  0x7ffc8bb6cbe0 : 0xea9260 : 6

预期输出:

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  0x7ffc8bb6cbe0 : 0xea9260 : 200

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  differentAddress: 0xea9260 : 200

第二个代码变体(片段)

仍然相信编译器优化的错误,我添加了步骤(睡眠,获取,睡眠,复制)。

  if (fork()){ //Parent
    *p= 200;
    printf("Parent: %p : %p : %i\n", &p, p, *p);
    wait(NULL);
  }else{ //Child
    sleep(2);
    uintptr_t fetch= (uintptr_t)p;
    sleep(2);
    p= (int*)fetch;
    printf("Child:  %p : %p : %i\n", &p, p, *p);
  }

这也没有改变实际输出。

环境

  • 语言C(可能是C11)
  • clang 7.0.0(我没有通过任何O1、O2、O3...标志。)
  • 编译器: 平台:https://replit.com/
  • 平台:Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
  • 机器:x86_64

我在理解这一点的其他尝试中

也尝试了其他类似的实验。这给我提供了模棱两可的结论。

The goal

Understanding what happens in the code and what have I misconcluded / mispredicted.

Context

While experimenting with fork function (and reading articles I probably misunderstood) I concluded that data used by child was a copy of parent's data.

  1. In order to make a child work on the same data as its parent, I created pointer p, assuming that its value will be the same in all (both) processes after forking.
  2. I made sure that both child's and parent's pointer was pointing to the same memory space by printing values stored by them. What stroke me to the ground, is that they also seem to be the same/exact – have the same addresses.
    Shall the 2 exact pointers point to different values? In my code they did.
  3. Next, to be sure that a compiler would not perform any optimization, I marked the p pointer as volatile.
    That did not change anything. Here is the code.

The general code

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


int main(){
  volatile int *volatile p= malloc(sizeof(int));
  *p= 6;
  

  if (fork()){ //Parent
    *p= 200; //Parent changes the value in "shared" memory

    printf("Parent: %p : %p : %i\n", &p, p, *p);
    wait(NULL);
  }else{ //Child
    sleep(3); //Child sleeps when parent is setting the "shared" value.

    printf("Child:  %p : %p : %i\n", &p, p, *p); //Child should read the same value.
  }
}

Output:

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  0x7ffc8bb6cbe0 : 0xea9260 : 6

Expected outputs:

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  0x7ffc8bb6cbe0 : 0xea9260 : 200

Or

Parent: 0x7ffc8bb6cbe0 : 0xea9260 : 200
Child:  differentAddress: 0xea9260 : 200

2nd code variation (snippet)

Still believing in the fault of compiler optimization, I added steps (sleep, fetch, sleep, copy).

  if (fork()){ //Parent
    *p= 200;
    printf("Parent: %p : %p : %i\n", &p, p, *p);
    wait(NULL);
  }else{ //Child
    sleep(2);
    uintptr_t fetch= (uintptr_t)p;
    sleep(2);
    p= (int*)fetch;
    printf("Child:  %p : %p : %i\n", &p, p, *p);
  }

This also changed nothing in the actual output.

Environment

  • Language C (propably C11)
  • Compiler: clang 7.0.0 (I haven't pass any of O1,O2,O3,... flags.)
  • IDE & platform: https://replit.com/
  • Platform: Linux-5.11.0-1029-gcp-x86_64-with-glibc2.27
  • Machine: x86_64

My other attempts at understanding this

I tried also other similar experiments. That provided me with ambiguous conclusions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(1

寂寞美少年 2025-01-18 13:03:22

操作系统为每个进程创建一个虚拟地址空间。进程访问内存时,并不是直接通过物理地址来访问内存。无论进程使用什么地址,计算机处理器都会将其从虚拟地址转换为物理地址。该转换由操作系统控制:每个进程都有自己的从虚拟地址到各种物理地址的映射。每个进程在很大程度上都有自己不同的物理内存。

当进程调用fork时,操作系统会创建该进程的副本。对于由一个处理器另一个处理器修改的任何内存,操作系统会在单独的物理内存中创建一个副本并调整地址转换。即使两个进程使用相同的虚拟地址来访问内存,它也可能引用不同的物理内存。

(为了提高效率,任何只被进程读取的内存通常都是共享的:它们的虚拟地址被映射到相同的物理地址,并且内存中的数据只有一个物理副本。当进程第一次调用 fork< /code>,即使两个进程都有写入内存的权限,它们也可能使用相同的内存。当它们实际写入内存时,操作系统会复制该部分内存并调整地址转换。)

进程有可能共享它们写入的物理内存,但这必须通过调用显式请求诸如shmat之类的例程来管理共享内存。

The operating system creates a virtual address space for each process. When a process accesses memory, it does not directly access memory by physical address. Whatever address the process uses is translated by the computer processor from a virtual address to a physical address. That translation is controlled by the operating system: Each process has its own map from virtual addresses to various physical addresses. Each process has largely its own different physical memory.

When a process calls fork, the operating system creates a copy of the process. For any memory that is modified by one processor the other, the operating system creates a copy in separate physical memory and adjusts the address translation. Even though two processes use the same virtual address to access memory, it may refer to different physical memory.

(For efficiency, any memory that is only read by processes is generally shared: Their virtual addresses are mapped to the same physical addresses, and there is only one physical copy of the data in memory. When a process first calls fork, both processes may use the same memory even though they have permission to write to memory. When they actually write to memory, then the operating system copies that portion of memory and adjusts the address translation.)

It is possible for processes to share physical memory that they write to, but this must be explicitly requested by calling routines such as shmat to manage shared memory.

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