I set a global variable n=2
, and then I created a child process using fork()
,Then I modify the value of n in the parent-child process and print, --n
in child process and ++n
in parent process.And print()
them, then I got 2 1 3
output. But I continued to print the address of n
in the parent and child processes and found that they pointed to the same address.
I know modern linux adopt Copy on Write
strategy, Only when a process attempts to modify memory does the operating system allocate new physical memory for the modified memory page and write the modified content into it. The original memory page remains reserved for the other process. So my question is why both n are pointing to the same address?
Here is my code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <wait.h>
volatile int n=2;
int main() {
pid_t pid;
printf("%d\n",n);
pid = fork();
if (pid < 0) {
perror("Fork failed");
exit(1);
} else if (pid == 0) {
--n;
printf("%p\n",&n);
printf("%d\n",n);
exit(0);
} else {
wait(NULL);
++n;
printf("%p\n",&n);
printf("%d\n",n);
}
return 0;
}
the output is
2
0x55af5a07e010
1
0x55af5a07e010
3
In a system with virtual memory, each process has its own address space. Roughly, each process thinks it has all the memory to itself. Pointers are addresses within this memory space. It doesn't refer to a physical location in memory. The physical location of a variable can change over time, but that's all transparent to the process.
So, since the two variables are in different processes, the pointers refer to places in different address space, and the fact that the two variables have the same address doesn't mean there's really only one variable.
Let's illustrate the scenario. Say the variable is in the page that starts at 0x1000.
Before fork:
Process 1's
Virtual Memory
+-------------+
| |
| |
⋮
| | Page in physical memory
| | or on disk or ...
+-0x1000------+ +-------------+
| |------------->| n |
+-------------+ maps to +-------------+
| |
| |
⋮
| |
| |
+-------------+
After fork, but before you modify the page/var:
Process 1's Process 2's
Virtual Memory Virtual Memory
+-------------+ +-------------+
| | | |
| | | |
⋮ ⋮
| | Page in physical memory | |
| | or on disk or ... | |
+-0x1000------+ +-------------+ +-0x1000------+
| |------------->| n |<-------------| |
+-------------+ maps to +-------------+ maps to +-------------+
| | This is shared | |
| | | |
⋮ ⋮
| | | |
| | | |
+-------------+ +-------------+
After you modify the page/var:
Process 1's Process 2's
Virtual Memory Virtual Memory
+-------------+ Different +-------------+
| | pages in physical memory | |
| | or on disk or ... | |
⋮ ⋮
| | +-------------+ | |
| | +------>| n | maps | |
+-0x1000------+ | +-------------+ to +-0x1000------+
| |------+ +------| |
+-------------+ maps +-------------+ | +-------------+
| | to | n |<------+ | |
| | +-------------+ | |
⋮ ⋮
| | | |
| | | |
+-------------+ +-------------+
The var is still at the same place in the address space, but the page that's mapped to that location that contains it is cloned.