您的位置:首页 > 运维架构 > Linux

29-fork 函数与文件共享

2016-12-19 16:07 218 查看
不知道大家考虑过这样的问题没:如果进程在 fork 之前打开了一些文件,那么 fork 完之后,这些文件的描述符是共享的,还是不共享的?

聪明的同学阅读了上篇《进程空间》的相关内容,脑子应该立即反应过来:父子进程的进程地址空间都是隔离的啊!所以打开的文件,应该也互不影响吧!

No! No! No! 很抱歉,上一篇我的确讲过进程空间是隔离的。为了循序渐近和压缩篇幅,我不得不相关内容挪到此篇。

进程 4GB 空间并不是完全隔离的。

实际上进程空间被分割为用户空间和内核空间。对于32 位 linux 来说,从 0-3GB 的空间是用户空间,从 3GB - 4GB 是内核空间。对于一个进程来说,是绝对无法读写内核空间的。

最重要的一点,或者精确一点,进程的用户空间是隔离的,而内核空间是共享的。看起来有点像下面的图。



图 1 进程的用户空间和内核空间

理解这一点也相当重要,这将为未来的进程通信带来可能!

1. 回忆描述符

对于一个进程来说,它所有打开的描述符,都会有记录。而且这些记录,保存该进程的 PCB 结构体中(PCB位于内核空间),该结构体有一个成员
struct file *flip[NR_OPEN]
,就保存了所有打开的文件(linux 0.11)。如图 2。



图2 进程打开的文件

有一点要注意的是,struct file 结构体中的 f_inode 并不是真的直接指向磁盘文件,这中间需要经过若干的步骤,不过为了方便起见和理解,这里直接指向了磁盘文件。

2. fork 后的样子

当图 2 所示的进程 fork 后,为变成下面这个样子。



图3 fork 后的两个进程打开的文件

这时候,struct file 中的 f_count 都会自增 1.

上图告诉我们的一个事实是,fork 完后的父子进程,共享 struct file 结构(因为该结构位于内核空间)。在《APUE》 这本书中,把 struct file 称为文件表。

3. 实验

理解了前面的内容后,不如做个实验看看是否真的是这样。下面这段程序在 fork 之前以写的方式创建了一个文件 test.txt。然后 fork 出的子进程立即向文件中写入
“world”
,然后睡眠5秒。而父进程在 fork 后睡眠3秒后向 test.txt 写入
"hello"
,并关闭描述符。子进程恢复后,又向 test.txt 文件中写入
"lalala"
后关闭描述符,结束。

代码

// forkwrite.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main() {
int fd = open("test.txt", O_WRONLY | O_CREAT, 0664);
if (fd == -1) {
perror("open");
return 1;
}
printf("I'm father\n");
printf("before fork\n");

pid_t pid = fork();
if (pid > 0) {
sleep(3);
printf("I'm father; I'm writing test.txt...\n");
write(fd, "hello", 5);
close(fd);
}
else if (pid == 0) {
printf("I'm child; I'm writing test.txt...\n");
write(fd, "world", 5);
sleep(5);
write(fd, "lalala", 6);
close(fd);
}
else {
perror("fork");
return 1;
}
return 0;
}


编译

$ gcc forkwrite.c -o forkwrite


运行

$ ./forkwrite


结果

屏幕打印:

I'm father
before fork
I'm child; I'm writing test.txt...
I'm father; I'm writing test.txt...


生成的 test.txt 文件内容:

worldhellolalala


4. 总结

理解用户空间和内核空间

知道内核空间是所有进程共享的

加深对文件描述符的理解

除了打开的文件外,父进程的很多其他性质也会被子进程共享,比如各种 ID 号、当前工作目录、根目录、资源的限制、信号屏蔽字、进程环境、文件打开执行时关闭标志、共享存储段。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息