01 虚拟地址
Linux系统中,fork()
函数创建的子进程,会忠实的将父进程的内存内容进行拷贝,尽管在fork()
函数之前定义的变量在各自进程块中的虚拟地址相同,但是不同进程对其的操作是相互隔离的,而不管是fork()
之前的全局变量、静态变量还是局部变量,都是如此。
如果想使得两个进程操作同一块物理地址,可以使用共享内存的方式,也可以用内存映射(MMP)的方式。
02 Show me the code
地址相同只是虚拟地址相同,而相同的虚拟地址在不同进程中映射不同的物理地址。
以下面的代码表明,变量初始化为0,先由父进程将其赋值为10,之后再由子进程将其赋值为20,最终的输出来看他们地址相同,却有不同的值。
因为这里的地址是虚拟地址,并不是物理地址,所以两个进程对三个变量的操作从始至终都是互相隔离的。
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
int global_val = 0; // 全局变量
static int static_val = 0; // 静态变量
int main() {
int local_val = 0; // 局部变量
// 创建子线程
int id = fork();
assert(id >= 0);
if (id > 0) { // 父进程
global_val = 10;
static_val = 10;
local_val = 10;
} else { // 子进程
// 确保父进程操作完毕
usleep(10);
global_val = 20;
static_val = 20;
local_val = 20;
}
// 确保父子进程均操作完毕
sleep(1);
// 打印结果
if (id > 0) {
printf("pid= %d\n", getpid());
printf("global_val地址:%x, 值:%d\n", &global_val, global_val);
printf("static_val地址:%x, 值:%d\n", &static_val, static_val);
printf("local_val地址:%x, 值:%d\n", &local_val, local_val);
} else {
sleep(1);
printf("pid= %d\n", getpid());
printf("global_val地址:%x, 值:%d\n", &global_val, global_val);
printf("static_val地址:%x, 值:%d\n", &static_val, static_val);
printf("local_val地址:%x, 值:%d\n", &local_val, local_val);
}
// 确保均打印完毕
sleep(2);
return 0;
}
03 输出
pid= 54317
global_val地址:2040, 值:10
static_val地址:2044, 值:10
local_val地址:efbff548, 值:10
pid= 54324
global_val地址:2040, 值:20
static_val地址:2044, 值:20
local_val地址:efbff548, 值:20