使用fork创建的新进程,但为变量打印相同的地址

时间:2016-08-05 11:20:25

标签: c operating-system fork

我有以下代码:

#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时会创建一个新的变量副本。它与虚拟地址和物理地址有什么关系吗?如果是这样,同一个虚拟地址如何映射到不同的物理地址?

3 个答案:

答案 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映射只能在   子。

         

    ...

  •