问题描述
根据Linux程序员手册,在调用fork
之后,父进程和子进程共享打开的文件描述符和文件偏移。
另一方面,已知glibc的stdio实现缓冲。因此,对scanf
的调用会导致文件偏移(读取)移动得远大于返回给最终用户的字节数,其余数据将存储在缓冲区中,以备下次调用。
但是当我执行以下操作时会发生什么:
- 致电
fork
。现在,父母和孩子共享stdin
。 - 在子进程中调用
scanf
。默认情况下,stdin
被块缓冲,所以scanf
读取块。 - 检查子文件中的文件偏移量。
- 从子进程中退出。
- 在父进程中等待子进程。
- 检查父级
stdin
中的文件偏移量。
根据glibc manual,当main
返回时,
所有打开的流均已正确关闭。
并在结束时
所有缓冲输入被丢弃
因此,我希望父母的stdin
文件偏移量位于孩子的scanf
停止读取(实际上停止读取)的位置。但是我将父级的stdin
文件偏移移回到返回给用户的输入结束位置。
我通过手册和互联网进行搜索,但没有发现任何描述此行为的信息。是否已指定?
这是我的代码:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main() {
int fd = fileno(stdin);
printf("Begin pos: %ld\n",lseek(fd,SEEK_CUR));
pid_t pid = fork();
if (pid == 0) {
char buffer[4096] = {};
int readed = scanf("%s",buffer);
printf("Child readed: %d,pos: %ld\n",readed,SEEK_CUR));
return 0;
}
int status = 0;
wait(&status);
printf("Parrent pos: %ld\n",SEEK_CUR));
return 0;
}
此处输出:
> echo "aaa bbb ccc" > test
> ./a.out < test
Begin pos: 0
Child readed: 1,pos: 12
Parrent pos: 3
解决方法
观察到的行为符合fclose
函数的POSIX要求:
如果该文件尚未在EOF上并且可以搜索,则如果流是基础文件的活动句柄,则应将基础打开文件描述的文件偏移设置为流的文件位置。文件说明。