Fork --- 父子进程继承文件操作符与fork()顺序引发的问题

父子进程继承文件操作符与fork()顺序引发的问题

目录

父子进程继承文件操作符与fork()顺序引发的问题

父进程先打开文件,再进行fork()操作

先进行fork()操作,父进程再打开文件

 总结:




Linux的进程描述task_struct{}中有一个数组专门用于记录一打开的文件,其中文件描述符作为该数组的下标,数组元素为指向所打开的文件所创建的文件表项。文件表项是用于描述文件当前被某个进程打开后的状态信息,包括文件状态标志,记录当前文件读取的位移量(可以通过接口lseek设置),以及文件的i节点指针(i节点描述文件的具体信息,如:创建,修改时间,文件大小,文件存储的块信息)。

文件描述符:其相当于一个逻辑句柄,而open等函数则是将文件或者物理设备与句柄相关联。句柄是一个整数,可以理解为进程特定的文件描述符表的索引。

文件描述符表:用户区的一部分,除非通过使用文件描述符的函数,否则程序无法对其进行访问。对进程中每个打开的文件,文件描述符表都包含一个条目。
           系统文件表:为系统中所有的进程共享。对每个活动的open, 它都包含一个条目。每个系统文件表的条目都包含文件偏移量、访问模式(读、写、or 读-写)以及指向它的文件描述符表的条目计数。
          内存索引节点表: 对系统中的每个活动的文件(被某个进程打开了),内存中索引节点表都包含一个条目。几个系统文件表条目可能对应于同一个内存索引节点表(不同进程打开同一个文件)。

 


  • 父进程先打开文件,再进行fork()操作

子进程和父进程的文件描述符所对应的文件表项是共享的,这意味着子进程对文件的读写直接影响父进程的文件位移量,父子进程文件描述符是共享的,但是关闭的时候可以分别关闭,也可以同时在公有代码中关闭。

Fork --- 父子进程继承文件操作符与fork()顺序引发的问题


#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>

#include<sys/wait.h>
#include<fcntl.h>
int main()
{

    
    int fd=open("a.txt",O_RDONLY);
    assert(fd!=-1);
    char buff[128]={0};
    pid_t pid=fork();
    assert(pid!=-1); 
         
    if(pid==0)
    {  
        printf("child:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        sleep(1);
        printf("child:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        
    }
    else
    {

        int val=0;
        wait(&val);
        printf("current id=%d\n",getpid());
        printf("exit code:%d\n",val);
        printf("parent:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        sleep(1);
        printf("parent:\t");        
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
    }
    close(fd);
    exit(3);
}


Fork --- 父子进程继承文件操作符与fork()顺序引发的问题


  • 先进行fork()操作,父进程再打开文件

子进程和父进程的文件描述符所对应的文件表项不是共享的,这意味着子进程对文件的读写不会影响父进程的文件位移量。(各走各的,节点指针在各自进程中变化,不会互相影响)。

Fork --- 父子进程继承文件操作符与fork()顺序引发的问题

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>

#include<sys/wait.h>
#include<fcntl.h>
int main()
{

    pid_t pid=fork();
    assert(pid!=-1); 
    int fd=open("a.txt",O_RDONLY);
    assert(fd!=-1);
    char buff[128]={0};
         
    if(pid==0)
    {  
        printf("child:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        sleep(1);
        printf("child:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        
    }
    else
    {

        int val=0;
        wait(&val);
        printf("current id=%d\n",getpid());
        printf("exit code:%d\n",val);
        printf("parent:\t");
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
        sleep(1);
        printf("parent:\t");        
        read(fd,buff,1);
        printf("buffer=%s\n",buff);
    }
    close(fd);
    exit(3);
}


Fork --- 父子进程继承文件操作符与fork()顺序引发的问题


 

  •  总结:

    (1)子进程继承父进程中打开的文件;父进程先open打开1个文件得到fd,然后再fork创建子进程,之后在父子进程中各自write向fd中写入内容;测试结论是接续写,实际上本质原因是父子进程之间的fd对应的文件指针是彼此关联。 
    (2)父子进程各自独立打开相同文件实现共享;父进程open打开test.txt然后写入,子进程打开test.txt然后写入,测试结论是分别写,原因是父子进程分离后才各自打开的test.txt,这时候该两个进程的PCB已经独立了,文件表也独立了,则2次读写是完全独立的。