Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C fork()系统调用和进程的内存空间_C_Operating System_Fork - Fatal编程技术网

C fork()系统调用和进程的内存空间

C fork()系统调用和进程的内存空间,c,operating-system,fork,C,Operating System,Fork,我引用Silberschatz的“操作系统概念”解决方案中的“当一个进程使用fork()调用创建一个新进程时,只有共享内存段在父进程和新分叉的子进程之间共享。堆栈和堆的副本是为新创建的进程创建的” 但是当我尝试这个程序的时候 #include <stdio.h> #include <sys/types.h> #define MAX_COUNT 200 void ChildProcess(void); /* child proc

我引用Silberschatz的“操作系统概念”解决方案中的“当一个进程使用fork()调用创建一个新进程时,只有共享内存段在父进程和新分叉的子进程之间共享。堆栈和堆的副本是为新创建的进程创建的”

但是当我尝试这个程序的时候

#include  <stdio.h>
#include  <sys/types.h>

#define   MAX_COUNT  200

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
         pid_t  pid;
         char * x=(char *)malloc(10);

         pid = fork();
         if (pid == 0) 
            ChildProcess();
         else 
            ParentProcess();
        printf("the address is %p\n",x);
}

void  ChildProcess(void)
{
          printf("   *** Child process  ***\n");
}

void  ParentProcess(void)
{
         printf("*** Parent*****\n");
}
父级和子级打印堆中的相同地址


有人能解释一下这里的矛盾吗。请清楚说明父母和孩子在记忆空间中共享的所有内容

地址相同,但地址空间不同。每个进程都有自己的地址空间,因此父进程的0x1370010与子进程的0x1370010不同。

是的,这两个进程对此变量使用相同的地址,但这些地址由不同的进程使用,因此不在同一地址中


这意味着地址是相同的,但它们不指向相同的物理内存。要理解这一点,您应该阅读更多关于虚拟内存的内容。

当内核
fork()
启动进程时,复制的内存信息会继承相同的地址信息,因为堆是按原样有效复制的。如果地址不同,您将如何更新自定义结构内部的指针?内核对这些信息一无所知,因此这些指针将失效。因此,物理地址可能会更改(事实上,即使在可执行文件的生命周期内,即使没有
fork()
ing,物理地址也会更改,但逻辑地址保持不变。

您可能正在具有虚拟内存的操作系统上运行程序。
fork()之后
call,父进程和子进程有单独的地址空间,因此地址
0x1370010
不指向同一个位置。如果一个进程写入
*x
,另一个进程将看不到更改。(事实上,这些可能是相同的内存页,甚至是交换文件中的相同块,直到它被更改,但操作系统确保在父级或子级写入该页时立即复制该页,只要程序能够确定它正在处理自己的副本。)

从另一个线程引用我自己

  • 当发出fork()系统调用时,所有页面的副本 创建与父进程相对应的进程,并将其加载到单独的 操作系统为子进程指定的内存位置。但这不是 在某些情况下需要考虑。 “exec”系统调用或在fork()之后很快退出 子进程只需要执行父进程的命令, 不需要复制父进程的页面,因为exec 将调用它的进程的地址空间替换为 要执行的命令

    在这种情况下,使用了一种称为写时复制(COW)的技术 使用这种技术,当出现fork时,父进程的页面不会被删除 为子进程复制。相反,这些页面在子进程之间共享 子进程和父进程。无论何时进程(父进程或子进程) 修改页面时,只制作该特定页面的单独副本 对于执行修改的进程(父进程或子进程)。 然后,此过程将使用新复制的页面,而不是 在将来的所有引用中共享一个进程。另一个进程 未修改共享页面)继续使用的原始副本 页面(现在不再共享)。此技术称为 写入时复制,因为某些进程写入页面时会复制该页面

  • 另外,为了理解为什么这些程序似乎使用相同的内存空间(事实并非如此),我想引用《操作系统:原理与实践》一书的一部分

    大多数现代处理器都引入了一种称为 虚拟地址。使用虚拟地址,每个进程的内存 从“相同”位置开始,例如零。 每个进程都认为自己拥有整个机器,尽管 显然,事实并非如此

    因此,这些虚拟地址是物理地址的转换,并不代表相同的物理内存空间,为了留下一个更实际的例子,我们可以做一个测试,如果我们编译并运行多次显示静态变量方向的程序,比如这个程序

    #include <stdio.h>
    
    int main() {
        static int a = 0;
    
        printf("%p\n", &a);
    
        getchar();
    
        return 0;
    }
    
    #包括
    int main(){
    静态int a=0;
    printf(“%p\n”、&a);
    getchar();
    返回0;
    }
    
    不可能在两个内存中获得相同的内存地址 不同的程序如果我们直接处理物理内存

    通过多次运行该程序得到的结果是令人满意的


两种情况下的“是”地址是相同的。但如果您在子进程和父进程中为x指定不同的值,然后还打印x值和x地址,您将得到答案

#include  <stdio.h>
#include  <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#define   MAX_COUNT  200

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
    pid_t  pid;
    int * x = (int *)malloc(10);

    pid = fork();
    if (pid == 0) {
            *x = 100;
            ChildProcess();
    }
    else {
            *x = 200;
            ParentProcess();
    }
    printf("the address is %p and value is %d\n", x, *x);
}

void  ChildProcess(void)
{
    printf("   *** Child process  ***\n");
}

void  ParentProcess(void)
{
    printf("*** Parent*****\n");
}

现在,您可以看到值不同,但地址相同。因此两个进程的地址空间不同。这些地址不是实际地址,而是逻辑地址,因此对于不同的进程,这些地址可能相同。

作为一种优化技术,虚拟内存一开始指向相同的物理内存呃fork(),但如果其中一个进程写入内存,内存将被复制,映射将被更改。但不幸的是,我无法复制您的实验。我在ArchLinux x64机器和MacOs High Sierra机器上运行了相同的程序:每次运行时,这两个机器都会产生非常不同的地址空间。一切都可以接受图片结果的表格。这是不确定的,也就是说,它取决于操作系统。请看下面的图片-->@solidak,Patricio的屏幕截图是Windows的。Windows不启用地址空间布局随机化
#include  <stdio.h>
#include  <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#define   MAX_COUNT  200

void  ChildProcess(void);                /* child process prototype  */
void  ParentProcess(void);               /* parent process prototype */

void  main(void)
{
    pid_t  pid;
    int * x = (int *)malloc(10);

    pid = fork();
    if (pid == 0) {
            *x = 100;
            ChildProcess();
    }
    else {
            *x = 200;
            ParentProcess();
    }
    printf("the address is %p and value is %d\n", x, *x);
}

void  ChildProcess(void)
{
    printf("   *** Child process  ***\n");
}

void  ParentProcess(void)
{
    printf("*** Parent*****\n");
}
*** Parent*****
the address is 0xf70260 and value is 200
*** Child process  ***
the address is 0xf70260 and value is 100