600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 文件描述符(多进程对同一个文件操作)

文件描述符(多进程对同一个文件操作)

时间:2020-06-11 11:41:41

相关推荐

文件描述符(多进程对同一个文件操作)

进程文件描述符:filedescrption,实际上我们调用open打开文件后得到的一个句柄,是个整数。属于用户区用来记录文件的一些信息,如文件指针,指向系统文件描述符表的指针,保存在进程的PCB中。得到的整数可以认为是系统描述符表的一个索引,实际上内核利用的是hash表完成系统文件描述符表,得到数字利用哈希算法得到相应struct file {}的内容。

标准输入STDIN fd = 0标准输出 STDOUT fd = 1标准错误输出 STDERR fd = 2包含在 unistd.h 文件中我们用户进程打开的文件最少从3开始,前三个文件描述符已经被占用,因为fd也是一种系统资源在打开一个文件时,文件描述符总是从选择可以使用的文件描述符中最小的一个当我们打开一个文件的时候:int fd = open();返回的句柄fd对应着一个结构体,而fd是用来索引系统的文件描述符表系统描述符表保存的是file_struct{ ... }

系统文件描述符表:为系统所所有进程所共享,每次open他都会包含一个条目。每个系统文件表的条目都包含文件的偏移量访问模式以及文件引用计数等,即为文件描述符struct file{}中的内容。

linux内核定义的文件结构体内容:

struct file {.........struct pathf_path;//文件的路径#define f_dentryf_path.dentry#define f_vfsmntf_path.mntconst struct file_operations*f_op;//访问方式atomic_long_tf_count; //文件的引用计数,引用计数==0时,文件才会关闭unsigned int f_flags; //标志位mode_tf_mode; //读写等权限loff_tf_pos;//读到了哪个位置struct fown_structf_owner;unsigned intf_uid, f_gid; //文件所属uid,gidstruct file_ra_statef_ra;u64f_version;#ifdef CONFIG_SECURITYvoid*f_security;#endif/* needed for tty driver, and maybe others */void*private_data;.............};

进程中打开一个文件就得到一个文件描述符fd,这个文件描述符fd是文件描述符表fdtable中的一项,而每个进程的PCB都有一个指针指向内核中的文件描述符表,进程通过该指针 拿着文件描述符 对应文件描述符的某一项,就可以查到文件对应的结构体也就得到了文件的具体信息

之前,我们提到过,父子进程之间是共享文件描述符的。

父进程的文件描述符被拷贝给了子进程。因此父进程打开的所有文件描述符都在子进程中保存了(每个进程都有独立的描述符)。

我在面试的时候遇到过两种情景分析:

1.fork()之前就open了文件,并且读取了部分内容;

问题分析:在fork前就打开了文件,那么父子进程中的指针不是一样的,但是指向和内容却是一样的所以,父子进程都是共享这个文件的描述符,也就是父子进程的谁的操作都会影响另外一个假如子进程先读,读到一个位置,父进程再读,是不是会在子进程的基础上继续读,还是从头开始读。创建一个a.txt文件,写入内容:hello world跑个程序验证一下:#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();if(pid == 0){read(fd,buff,1);//我给buff中读进去1个字节内容printf("buff = %s\n",buff);}else if(pid > 0){sleep(5);//保证子进程可以先读文件read(fd,buff,2);//父进程中读取2个字节printf("buff = %s\n",buff);wait(NULL);}close(fd);return 0;}执行结果:buff = hbuff = el

根据现象得结论:

1.先open再fork,父子进程共享一个文件文件描述信息,包括引用计数、读取位置等等2.既然共享,那么上述现象不言而喻虽然,父子进程都读取了该文件,但是文件的引用计数始终 == 1,所以需要close一次即可可以在子进程代码分支中close,也可以在父进程代码分支close,还可以在公共部分close真正记录文件信息的表单处于内核,是所有进程共享的,子进程复制了父进程的指针内容,指向的是同一个文件描述符信息,发生上面的现象

2.fork()调用之后open文件:

我们将上面的代码做一个简单的修改。将open放到fork下面,文件a.txt内容不变,依旧是hello world程序验证:#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<string.h>#include<unistd.h>#include<sys/wait.h>#include<fcntl.h>int main(){char buff[128]={0};pid_t pid = fork();int fd = open("a.txt",O_RDONLY);assert(fd!=-1);if(pid == 0){read(fd,buff,1);//我给buff中读进去1个字节内容printf("buff = %s\n",buff);}else if(pid > 0){sleep(5);//保证子进程可以先读文件read(fd,buff,2);//父进程中读取2个字节printf("buff = %s\n",buff);wait(NULL);}close(fd);return 0;}执行结果:buff = hbuff = he

根据现象得结论:

从执行结果我们可以发现,父子进程都是从文件开始处读取,并没有共享 读取位置等信息此时文件得描述信息不再是共享得了。而是每个进程都有自己得一份,所以两个进程读写操作都是互不影响得的不同的是一个文件别打开两次,引用计数 == 2文件表存在于内核,fork之后,父子进程指针指向的不是同一个描述信息,因为PCB已经独立文件表也独立

总结:

fork前进行open,子进程无条件继承父进程的文件描述信息,子进程和父进程指向一样文件描述信息

fork后进行open,子进程可以有自己的选择啊,不用继承父进程的所有,比如文件描述信息

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。