嵌入式Linux 2020-07-14

Linux fork的写时复制_嵌入式

这个问题是一个同学在知识星球里面提问的

看下面的代码

#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <sys/wait.h>
#include <string.h>
  
int main(){  
        int fd;  
        char c[10];  
        char *child = "#>Child.....output\n";  
  
        fd = open("foobar.txt",O_RDWR|O_CREAT,0666);  
        printf("fd:%d\n",fd); 
        write(fd,"foobar.txt",7);
        close(fd);

        //父进程  
        fd = open("foobar.txt",O_RDONLY,0);
        printf("fd:%d\n",fd);
        if(fork()==0)//子进程
        {  
                fd = 1;//stdout
                write(fd,child,strlen(child)+1);
                exit(0);  
        }  
        printf("fd:%d\n",fd);
        read(fd,c,sizeof(c));
        close(fd); 
        c[10]='\0';  
        printf("c = %s\n",c);  
        exit(0);  
}  

先不要往下看,猜测下这个代码的输出是啥

特别是 fd 在fork出来的进程里面进行了修改,那是不是读出来的内容会是不对的呢?

实际输出如下:

weiqifa@bsp-ubuntu1804:~/linux$ gcc forkc4.c && ./a.out
fd:3
fd:3
fd:3
c = foobar
#>Child.....output
weiqifa@bsp-ubuntu1804:~/linux$

这涉及一个知识点,叫做写时复制,就是在使用的使用,我再分配实际的物理内存给子进程,如果没有需要使用的资源,那我就还是用父进程的东西。

fork函数用于创建子进程,典型的调用一次,返回两次的函数,其中返回子进程的PID是0,其中调用进程返回了子进程的PID,而子进程则返回了0,这是一个比较有意思的函数。

但是两个进程的执行顺序是不定的。fork()函数调用完成以后父进程的虚拟存储空间被拷贝给了子进程的虚拟存储空间,因此也就实现了共享文件等操作。

但是虚拟的存储空间映射到物理存储空间的过程中采用了写时拷贝技术(具体的操作大小是按着页控制的),该技术主要是将多进程中同样的对象(数据)在物理存储其中只有一个物理存储空间,而当其中的某一个进程试图对该区域进行写操作时,内核就会在物理存储器中开辟一个新的物理页面,将需要写的区域内容复制到新的物理页面中,然后对新的物理页面进行写操作。这时就是实现了对不同进程的操作而不会产生影响其他的进程,同时也节省了很多的物理存储器。

写时复制的技术让操作系统大大降低了实际的物理内存空间。

参考:

https://www.cnblogs.com/wuchanming/p/4495479.html


推荐阅读:专辑|Linux文章汇总专辑|程序人生专辑|C语言