首先,我们来看一个实例:
process_fork3.c
/*
* process_fork3.c
*
* Created on: 2016-11-13
* Author: river
*/
/*
* process_fork.c
*
* Created on: 2016-11-11
* Author: river
*/
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
//全局变量
int g_v = 30;
int main()
{
int a_v = 30;//局部变量
static int s_v = 30;//静态变量
pid_t pid;
pid = fork();//创建子进程
//在fork之后会运行2个进程(父进程、子进程)
if(pid < 0)
{
perror("fork error");
}
else if(pid > 0)
{//父进程(在父进程中fork返回的是子进程的pid)
//父进程执行的代码...
g_v = 40;
a_v = 40;
s_v = 40;
printf("I am parent process pid is %d\n", getpid());
printf("g_v: %p, a_v: %p, s_v: %p\n\n\n", &g_v, &a_v, &s_v);
}
else
{//子进程(在子进程中fork返回的是0)
//子进程执行的代码...
printf("kkkpid: %d, g_v:%d, a_v:%d, s_v:%d\n", getpid(), g_v, a_v, s_v);//父子进程都执行
g_v = 50;
a_v = 50;
s_v = 50;
printf("I am child process pid is %d\n", getpid());
printf("g_v: %p, a_v: %p, s_v: %p\n\n\n", &g_v, &a_v, &s_v);
}
printf("pid: %d, g_v:%d, a_v:%d, s_v:%d\n\n\n", getpid(), g_v, a_v, s_v);//父子进程都执行
sleep(1);//睡眠1s使得父子进程可以交替运行
exit(0);
}
上面的例子,我们定义3个变量,分别是全局变量、局部变量、静态变量,并都赋予初始值30,在父进程中都修改为40,并打印三个变量的地址,在子进程中都修改为50,并打印三个变量的地址,最后父子进程分别打印三个变量的值。
程序运行输出结果为:
I am parent process pid is 21268
g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038
pid: 21273, g_v:30, a_v:30, s_v:30
pid: 21268, g_v:40, a_v:40, s_v:40
I am child process pid is 21273
g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038
pid: 21273, g_v:50, a_v:50, s_v:50
从上面的输出结果我们可以看到父进程的ID是21268,子进程的ID是21273,我们用绿色标示了父进程的输出信息,蓝色标示了子进程的输出信息。
对于pid: 21273, g_v:30, a_v:30, s_v:30这一句的解释是 在程序运行开始我们将三个变量都初始化为30,因此子进程在没有对三个变量进行修改之前,我们打印的三个变量的值是从父进程中继承而来的数值(注意父进程是在fork之后对三个变量修改为40的,所以父进程拷贝到子进程中的三个变量的值仍然是父进程初始化为30的值),这也就验证了上一篇文章中提到的子进程会遗留父进程中的数据。
我们会看到这样一个现象:
I am parent process pid is 21268
g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038
I am child process pid is 21273
g_v: 0x804a034, a_v: 0xbf8e1528, s_v: 0x804a038
父进程变量的地址与子进程变量的地址是一样的,也就是说不同的进程的变量却有相同的虚拟地址(注:程序中变量的地址都是虚拟地址,而非物理地址)。原因是内核会为每个进程分配4G的虚拟地址空间,这4G的虚拟地址空间地址分布都是一样的,由于子进程虚拟地址空间的数据都是从父进程中拷贝而来的,都是一样的,因此相同的数据在4G的虚拟地址空间中的分布也是一样的。那为什么相同的虚拟地址(变量地址)最终会得到不同的变量值呢?原因是虽然虚拟地址分布是一样的,但是由于相同的虚拟地址映射到不同的物理地址,所以我们才会得到不同的变量值。
下面的示图描了这一点:
从上图可以看到,虽然父进程与子进程中三个变量虚拟地址是一样的,但是映射到不同的物理地址就得到了不同的数值。