fork创建子进时关于文件操作(fwrite、fread)的那些事
来源:互联网 发布:战狼2知乎 编辑:程序博客网 时间:2024/05/28 15:21
今天有个朋友突然问我一个关于fork()创建子线程然后对文件操作的问题,当时我也楞了一下,好像没什么错,可是结果就是不如我所愿,看了一会才解决了那个问题,相信广大编程爱好者可能也会遇到该类问题,故现在把该问题写到微博。
问题:用fork创建一个子进程,然后先在父进程将hello写入到test.txt文件中,然后在子进程中将world写入到test.txt中,最后在父进程将welcome写入test.txt文件中,最后结果应为:helloworldwelcome
出现问题的解题程序是:
filename:fork_fwrite.c
#include<stdio.h>#include<fcntl.h>//perror()的头文件#include<string.h>int main(){FILE *fp;int id;char *hello="hello";char *world="world";char *welcome="welcome";char *filename="test.txt";if((fp=fopen(filename,"w+"))==NULL){perror("fopen");return ;}if(fwrite(hello,strlen(hello),1,fp)<1)//fwrite返回成功写入文件的块数printf("fwrite hello error!\n");if((id=fork())==-1){//创建进程,失败返回-1perror("fork");return;}if(id==0){//子进程if(fwrite(world,strlen(world),1,fp)<1)//fwrite返回成功写入文件的块数printf("fwrite world error!\n");}else{//父进程sleep(1);if(fwrite(welcome,strlen(welcome),1,fp)<1)//fwrite返回成功写入文件的块数printf("fwrite welcome error!\n");}fclose(fp);return 0;}
得到的结果是:
ok,看到这个结果就知道是错,那么为什么错了呢?下面是我的解释:
首先,先了解一下fork()工作的机制:对父进程的所有值都拷贝一份到子进程(包包括缓冲区的东西),但是拷贝过后,父/子进程对数据的操作是互相不影响,也就是说,他们是独立的,但是有一点就是:关于文件的操作有点特殊,对于文件的操作,他们是这样工作的,比如在父进程open一个文件,那么就会有一个文件描述符并且该文件描述符会有一个条目,并且在文件系统中也有相应的条目,当创建一个子进程时,文件描述符会自增一个条目,当在父/子进程调用了close函数时,文件描述符就会自减1,但是另一个的进程还可对该文件描述符进行操作,直到文件描述符的条目自减到0时,才关闭了文件描述符的作用。
所以上述代码的父/子进程都能执行fclose,但是当子进程先结束时,父进程还是可以对test.txt文件进行写入。
对于文件描述符、条目这部分可以参考
http://blog.csdn.net/cws1214/article/details/9703743。
而fwrite是带缓冲的,write不带缓冲,这个会有什么影响呢?如果你是用open()、read()、write()函数替换相应的fopen()、fread()、fwrite()函数,那么该问题完全不会出现,因为他是实时写入文件的,而fwrite是带缓冲的,相当于说把hello先放在缓冲区,没有写入到文件里面。
对于上述代码的执行顺序:
1)先将hello放入父进程缓冲区;
2)创建子进程,此时把父进程的缓冲区的值(hello)也拷贝过去,也就是说父子进程的缓冲区都有hello,但是还没有写入test.txt文件中。
3)子进程将world写入子进程的缓冲区里,此时子进程的缓冲区的值变为:helloworld
4)子进程执行fclose(fp),将子进程缓冲区的东西写入文件中,然后关闭文件(子进程就不能再访问该文件,但父进程还有访问读写权限),结束子进程。此时文件的内容变为:helloworld
5)父进程将welcome写入缓冲区里父进程的缓冲区,此时父进程的缓冲区的值为:hellowelcome
6)父进程调用fclose(fp)函数,此时会把缓冲区的值写入文件,所以才会得到文件值为:helloworldhellowelcome的结果。
对于使用write函数实现的代码如下:
filename:fork_write.c
#include<stdio.h>#include<fcntl.h>//perror()的头文件#include<string.h>int main(){int fd;int id;char *hello="hello";char *world="world";char *welcome="welcome";char *filename="test.txt";if((fd=open(filename,O_WRONLY))==-1){perror("fopen");return ;}if(write(fd,hello,strlen(hello))<1)//write返回成功写入文件的字节数printf("write hello error!\n");if((id=fork())==-1){//创建进程,失败返回-1perror("fork");return;}if(id==0){//子进程if(write(fd,world,strlen(world))<1)//write返回成功写入文件的字节数printf("write world error!\n");}else{//父进程sleep(1);if(write(fd,welcome,strlen(welcome))<1)//write返回成功写入文件的字节数printf("write welcome error!\n");}close(fd);return 0;}结果:
总结:
1、fork是拷贝值,包括缓冲区的值,而对于文件操作来说,父子进程是共享的,而且父子进程任意一个关闭文件时,另一个是不受其影响的,照样还可以访问。
2、fwrite是带缓冲区的,而write是不带缓冲区的,它可以实时写入。
- fork创建子进时关于文件操作(fwrite、fread)的那些事
- C/C++文件的操作(fread() fwrite())
- C/C++文件的操作(fread() fwrite())
- fopen、fread、fwrite文件操作
- C语言库函数文件操作(fread、fwrite、feof)
- C语言文件流操作的二进制读写和定位(fwrite、fread、fseek)
- C语言文件流关于fread,fwrite多读的问题(yuxinsong)
- C文件操作之fread,fwrite函数
- fread()和fwrite()函数读写文件操作
- 文件操作之fread()和fwrite()函数
- fread/fwrite实现文件的copy
- 关于fwrite,fread
- C/C++读写文件(fwrite,fread)
- fread/fwrite读写文件
- 读写文件 fread,fwrite
- 文件流:Fread&Fwrite
- 文件操作--标准I/O操作--fopen() fclose() fread() fwrite()
- 文件读写操作之一 <二进制读写操作> fwrite与fread
- 【转载】Java多线程编程2--同步锁定--synchronized同步方法、脏读、锁重入
- asp.net core 学习资料整理
- Android之Camera预览
- 【Day38】php微信扫码支付源码
- 学习Hadoop第二十八课(java通过调用接口来操作HBase)
- fork创建子进时关于文件操作(fwrite、fread)的那些事
- 红茶一杯话Binder(初始篇)
- 两种排序
- [LeetCode 239] Sliding Window Maximum (Queap/队列快速求最大值)
- Java复习1
- 红茶一杯话Binder(传输机制篇_上)
- c++初学
- 【转载】Java多线程编程2--同步锁定--死锁
- 红茶一杯话Binder(传输机制篇_中)