欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

多进程同时写一个文件会怎样?分别用write和fwrite去观察现象

发布时间:2025/6/15 编程问答 37 豆豆
生活随笔 收集整理的这篇文章主要介绍了 多进程同时写一个文件会怎样?分别用write和fwrite去观察现象 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一、问题还原
在多进程的环境下,父子进程同时去写一个文件,例如父进程每次写入aaaaa,子进程每次写入bbbbb,问题是会不会出现写操作被打断的现象,比如出现aabbbaaabb这样交替的情况?

二、结论
1:使用write系统调用的情况下,不会出现内容交叉的情况。 
2:使用fwriteANSIC标准C语言函数,会出现内容交叉的情况。

三、实验过程
实验环境:
操作系统: RedHat Linux 7.0

实验过程:
1:打开一个文件,fork一个子进程,父子进程同时写文件,父进程写入a,子进程写入b。

2:分别用write和fwrite去观察现象。

实验现象
write:不会出现数据交叉的情况,而且父子进程交替执行写入。
1:测试代码如下:

#include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> #include<sys/wait.h>int main(int argc,char * argv[]) {struct timeval start,end;int times = argc > 1 ? atoi(argv[1]):10000;  //通过参数传入需要写入的字节数int stat;int fd;int childpid;int i;for(i=0 ;i<1; i++){if(childpid = fork())break;}if(childpid == -1){perror("failed to fork\n");return 1;}fd = open("tmp.dat",O_WRONLY|O_CREAT|O_APPEND,0666);if(fd < 0){perror("failed to open\n");return 1;}gettimeofday(&start,NULL);          //测试下时间if(childpid > 0){char *buf = (char*)malloc(times);for(int i = 0;i < times;++i) {buf[i] = 'a';}strcat(buf,"\n");for(i=0; i<10; i++){usleep(1000);write(fd,buf,strlen(buf));}wait(&stat);}else{char *buf = (char*)malloc(times);for(int i = 0;i < times;++i) {buf[i] = 'b';}strcat(buf,"\n");for(i=0; i<10; i++){usleep(1000);write(fd,buf,strlen(buf));}}close(fd);gettimeofday(&end,NULL);int timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;printf("UseTime: MicroSeconds:%d us and  Seconds:%d s\n",timeuse,end.tv_sec-start.tv_sec);return 0; }


2:编译运行

$  gcc file.c -std=c99 -o file $ ./file 100


3:结果

可以发现首先没有出现交叉的情况,并且父子进程是交替写入的,即一行a,一行b。

fwrite:在写入的字节数为500的时候就会出现交叉的情况(当然,500并不是最准确的数字,只是我测试500的时候已经出现了)。
1:测试代码如下:

#include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/time.h> #include <sys/wait.h>int main(int argc,char * argv[]) {struct timeval start,end;int times = argc > 1 ? atoi(argv[1]):10000;int stat;int fd;int childpid;int i;for(i=0 ;i<1; i++){if(childpid = fork())break;}if(childpid == -1){perror("failed to fork\n");return 1;}FILE *fp = NULL;fp = fopen("tmpfp.dat","ab");if(fp == NULL) {system("touch tmpfp.dat");}gettimeofday(&start,NULL); if(childpid > 0){char *buf = (char*)malloc(times);for(int i = 0;i < times;++i) {buf[i] = 'a';}strcat(buf,"\n");for(i=0; i<10; i++){usleep(1000);fwrite(buf,strlen(buf),1,fp);}wait(&stat);}else{char *buf = (char*)malloc(times);for(int i = 0;i < times;++i) {buf[i] = 'b';}strcat(buf,"\n");for(i=0; i<10; i++){usleep(1000);fwrite(buf,strlen(buf),1,fp);}}fclose(fp);gettimeofday(&end,NULL); int timeuse = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;printf("UseTime: MicroSeconds:%d us and Seconds:%d s\n",timeuse,end.tv_sec-start.tv_sec);return 0; }


2:编译运行

$  gcc fileFP.c -std=c99 -o Filefp $ ./Filefp 500


3:结果

用一个sed的表达式判断下是否出现了交叉现象,因为我们是以行写入的,所以每行的开头不是a就是b,拿出所有a开头的行,看里面是否有包含b的。

$ sed -n '/^a.*$/p' tmpfp.dat | grep b// '/^a.*$/p'  表示以a开头 // grep b   表示过滤出包含b的行


可以看到,已经出现了一行a中混入了b,因此fwrite在多进程的情况下操作同一个fd是会出现问题的。

四、反思
1:为什么write不会出现问题但是fwrite却出现了问题?

答:write是Linux操作系统的系统调用,fwrite是ANSIC标准的C语言库函数,fwrite在用户态是有缓冲区的。因此需要锁机制来保证并发环境下的安全访问。 
http://www.cnblogs.com/ldp-web/archive/2011/10/21/2220180.html

2:如果两个进程同时write一个socket会怎样?

答:就像队列一样,一个进程写完另一个进程才能写,数据上不会有问题。 
http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid

参考资料:

http://bbs.chinaunix.net/thread-804742-1-1.html

http://www.chinaunix.net/old_jh/23/829712.html

https://www.nowcoder.com/questionTerminal/869cae279aa84d8b8e9e50cf1084830b
 

《新程序员》:云原生和全面数字化实践50位技术专家共同创作,文字、视频、音频交互阅读

总结

以上是生活随笔为你收集整理的多进程同时写一个文件会怎样?分别用write和fwrite去观察现象的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。