返回信息流#### 关于子进程与文件描述符的小问题
##### 现象描述:
我在main函数中打开了一个文件输入流,在while循环中逐行将文件中的内容打印出来。在while循环的打印语句之后fork一下,fork后的子进程直接exit,父进程则继续循环打印。然鹅编译运行这段代码,发现程序会将文件里面的内容**循环打印无数遍**。在子进程调用exit前增加一句fclose fp可以解决这个问题。
##### 问题:
为什么在增加语句fclose fp之前,程序会**重复打印**文件的内容?是子进程的exit操作改变了什么吗?在网上没有找到解答,球球各位大佬伸伸援手
`代码`如下
```c
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
int main(){
FILE* fp = fopen("./hello.txt","r");//打开文件流
char*str=NULL;
size_t size = 0;
while(getline(&str,&size,fp)!=-1){//在fp打开的文件中读取一行内容到str中
printf("%s",str);//打印str
//fork之后子进程exit,父进程继续打印
pid_t child = fork();
if(child==0){
//fclose(fp);//如果子进程关闭它的fp,问题就可以得到解决
exit(0);
}
else if(child >0)
{
wait(NULL);
continue;
}
}
return 0;
}
```
下面是`./hello.txt`的内容
```c
a
b
chard
elsed
fopen
```
图片:
添加fclose语句之前,文件内容被重复打印:
添加fclose语句之后的结果:
这是一条镜像帖。来源:北邮人论坛 / cpp / #101681同步于 2022/2/12
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
【问题】关于子进程与文件描述符的小问题
yoelee
2022/2/12镜像同步10 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
出现这个的原因是fork出来的进程与父进程共享文件表项,也共享文件的读取偏移量,但是当子进程 exit() 的时候,会帮你关闭这个文件(fclose),然后关闭这个文件的时候可能会将这个文件的偏移量回退,导致另一个进程读取进度也回退了,造成了这种死循环。解决办法是将调用的 exit() 替换为 _exit(),直接退出进程而不进行其他处理。参考:https://stackoverflow.com/a/54915495。具体细节可以看看这个答案里给出的链接。
另外,在我的wsl(Ubuntu 20.04)上,删掉你hello.txt的最后一行可以正常退出(不会死循环),不过仍然会重复读取数据。你直接fclose也有问题,会读取最后一行两次。
收到!谢谢大哥,我搞了一下午都没搞明白
【 在 RinChanNOW 的大作中提到: 】
: 出现这个的原因是fork出来的进程与父进程共享文件表项,也共享文件的读取偏移量,但是当子进程 exit() 的时候,会帮你关闭这个文件(fclose),然后关闭这个文件的时候可能会将这个文件的偏移量回退,导致另一个进程读取进度也回退了,造成了这种死循环。解决办法是将调用的 exit() 替换为 _exit(),直接退出进程而不进行其他处理。参考:https://stackoverflow.com/a/54915495。具体细节可以看看这个答案里给出的链接。
: --
我也是昨天看到你这个问题才去了解的,共同学习共同进步[ema21]
【 在 yoelee 的大作中提到: 】
: 收到!谢谢大哥,我搞了一下午都没搞明白
请问一下,既然偏移量回退了,为啥不是一直输出第一行数据呢?
【 在 RinChanNOW 的大作中提到: 】
: 我也是昨天看到你这个问题才去了解的,共同学习共同进步[ema21]
因为相当于重新从头开始读了,就变成和一开始一样了,造成了循环
【 在 hueru 的大作中提到: 】
: 请问一下,既然偏移量回退了,为啥不是一直输出第一行数据呢?
我上面说的有问题,回退不是会退到开头,具体我也不知道是回退多少,可以看看那个stackoverflow的回答。看他的描述应该是由于有两个进程都在读同一个文件,当一个进程读到EOF的时候,为了保证另一个进程也能正常读,需要回退到读之前的位置,不知道是不是这个意思。
【 在 hueru 的大作中提到: 】
: 是啊,那应该一直循环读第一行啊