我有以下代码:
#include<stdio.h>
#include<unistd.h>
int main()
{
int a=0;
printf("before: %d %p\n",a,&a);
int t=fork();
if(t==0)
{
a=a+5;
printf("child: %d %p\n",a,&a);
}
else
{
a=a+10;
printf("parent: %d %p\n",a,&a);
}
//printf("both: %d %p\n",a,&a);
return 0;
}
为什么所有地址都打印相同?我想在调用fork时会创建一个新的变量副本。它与虚拟地址和物理地址有什么关系吗?如果是这样,同一个虚拟地址如何映射到不同的物理地址?
答案 0 :(得分:6)
地址相同,因为每个process(父母和孩子)都有拥有 virtual address space。 Linux计算机有virtual memory(由内核和处理器提供)。
fork
system call&#34;神奇地&#34;将父进程的虚拟地址空间复制到子进程的虚拟地址空间(fork
的结果除外)。此复制使用惰性copy-on-write技术,因此非常有效。内核正在管理MMU(用于虚拟内存并实现每个虚拟地址空间)
阅读Advanced Linux Programming(它有几章与此相关)&amp;仔细fork(2)。
顺便说一下,习惯在fflush(NULL);
之前调用fork
。请参阅fflush(3)。
答案 1 :(得分:4)
因为Unix系统使用虚拟地址,而fork
会创建父进程的精确副本。这个精确的副本当然包括(初始)内存映射。
答案 2 :(得分:2)
因为那是fork()
所做的。每Filip Woj:
ent.MyTable.Where(e => e.MyDate.HasValue && e.Date.Value.Day == 12);
函数将创建一个新进程。 新流程 (子进程)应是调用进程的精确副本(父进程) 过程)除了详述如下:
子进程应具有唯一的进程ID。
子进程ID也不应与任何活动进程组ID匹配。
子进程应具有不同的父进程ID,该进程ID应为调用进程的进程ID。
子进程应拥有自己父文件描述符的副本。每个孩子的文件描述符都应参考
相同的打开文件描述以及相应的文件描述符 父母。子进程应拥有自己父开放目录流的副本。子进程中的每个打开的目录流
可以与相应的共享目录流定位 父目录流。子进程应拥有自己父级消息目录描述符的副本。
tms_utime,tms_stime,tms_cutime和tms_cstime的子进程值应设置为0.
闹钟信号重置为零所需的时间,并取消闹钟(如果有的话);见警报。
[XSI] [选项开始]应清除所有semadj值。 [选项结束]
子进程不会继承父进程设置的文件锁。
子进程待处理的信号集应初始化为空集。
[XSI] [选项开始]应在子进程中重置间隔计时器。 [选项结束]
在父进程中打开的任何信号量也应在子进程中打开。
[ML] [Option Start]子进程不得通过调用来继承父进程建立的任何地址空间内存锁 mlockall()或mlock()。 [选项结束]
在父进程中保留的内存映射应保留在子进程中。从父项继承的MAP_PRIVATE映射 也可以是子进程中的MAP_PRIVATE映射,以及对其的任何修改 父母在调用之前做出的这些映射中的数据 fork()对于孩子是可见的。对数据的任何修改 在fork()返回后由父项进行的MAP_PRIVATE映射 只有父母才能看到。对数据的修改 由孩子做出的MAP_PRIVATE映射只能在 子。
...