关联博文:
当文件操作遇上fork
Linux内核的文件结构体
struct file {
.........
struct path f_path; //文件的路径
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;//访问方式
atomic_long_t f_count; //文件的引用计数,引用计数值为0时,文件才会关闭
unsigned int f_flags; //标志位
mode_t f_mode; //读写等权限
loff_t f_pos; //读到了哪个位置
struct fown_struct f_owner;
unsigned int f_uid, f_gid; //文件所属uid,gid
struct file_ra_state f_ra;
u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
.............
};
文件的引用计数,引用计数值为0时,文件才会被关闭。
两种情景分析:
1.fork()之前就open了文件,并且读取了部分内容
#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("tmp.txt",O_RDONLY);
assert(fd!=-1);
char buff[10]={0};
pid_t pid = fork();
if(pid == 0){
read(fd,buff,1); //子进程读1个字节内容
printf("buff = %s
",buff);
}else if(pid > 0){
sleep(5); //保证子进程可以先读文件
read(fd,buff,2); //父进程读2个字节
printf("buff = %s
",buff);
wait(NULL); //收尸,不获取死因
}
close(fd);
return 0;
}
tmp.txt的内容为“niceday”
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process# gcc process.c -o ab
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process#
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process# ./ab
buff = n
buff = ic
小结:
先open再fork,文件只被打开一次,父子进程共享一个文件描述信息,包括引用计数、读取位置等等。
虽然父子进程都读取了该文件,由于文件的引用计数始终为1,所以只需要close一次即可。
可以在子进程代码分支中close,也可以在父进程代码分支close,还可以在公共部分close。
子进程复制了父进程的文件表项指针, 指向的是同一个文件表项,如下图:
2.fork()调用之后open文件
#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();
int fd = open("tmp.txt",O_RDONLY);
assert(fd!=-1);
char buff[10]={0};
if(pid == 0){
read(fd,buff,1); //子进程读1个字节内容
printf("buff = %s
",buff);
}else if(pid > 0){
sleep(5); //保证子进程可以先读文件
read(fd,buff,2); //父进程读2个字节
printf("buff = %s
",buff);
wait(NULL); //收尸,不获取死因
}
close(fd);
return 0;
}
tmp.txt的内容为“niceday”, 同上。
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process# gcc process.c -o ab
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process#
root@lmw-virtual-machine:/home/lmw/MINE/Linux_C_exercise/process# ./ab
buff = n
buff = ni
小结:
此时的文件描述信息不再是共享的,一个文件被打开了两次,即引用计数值为2,每个进程都有自己的一份,所以两个进程读写操作互不影响。
总结:
先open,再fork:子进程无条件继承父进程的文件描述信息,子进程和父进程指向同一个文件描述信息。
先fork,再open:子进程有自己的配置,和父进程的配置是相互独立的关系。所谓配置,例如文件描述信息。
文末,再来一幅图(不一样的精彩)
.