多进程同时写一个文件会怎样?

标签: write fwrite 读写fd socket
3953人阅读 评论(1) 收藏 举报
分类:

一、问题还原

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

二、结论

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

三、实验过程

实验环境:

操作系统: RedHat Linux 7.0

实验过程:

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

2:分别用writefwrite去观察现象。

实验现象

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却出现了问题?

答:writeLinux操作系统的系统调用,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

查看评论

写一个函数,确保多个进程同时写入一个文件成功

具体代码实现如下: /** * @param string $path 操作文件路径 * @param string $mode 打开文件方式 * @param string $data ...
  • CNYYGJ
  • CNYYGJ
  • 2016-12-06 10:29:57
  • 1051

多个进程对同一文件写入的问题

转载。 讨论关于并发环境下,多个进程对同一文件写入的问题,我们会涉及到文件共享的知识。在开始之前,我们先讨论一些有关文件共享的知识。 1. 文件共享   Unix系统支持在不同进程间共享打开...
  • lk07828
  • lk07828
  • 2016-10-14 10:00:14
  • 2234

多进程同时访问文件并发问题解决方法

因为业务需求需要多个进程同时访问某个文件并进行读写操作的需求,因为文件并不是被同一个进程访问,而且极大可能会发生多进程争抢文件句柄的情况,如果在同一个进程里不同的线程访问,或许还能使用线程锁的方式控制...
  • wsxqaz
  • wsxqaz
  • 2012-01-11 16:20:06
  • 16562

多进程、多线程并发写同一log文件问题

两个独立进程各自打开同一个文件 如果用O_APPEND标志打开了一个文件,则相应标志也被设置到文件表项的文件状态标志中。每次对这种具有添写标志的文件执行写操作时,在文件表项中的当前文件偏移量...
  • xhu_eternalcc
  • xhu_eternalcc
  • 2013-10-27 21:16:29
  • 5268

解决多进程或多线程同时读写同一个文件的问题

本文介绍一种在PHP中解决多进程或多线程同时读写同一个文件的问题。
  • lcy4599
  • lcy4599
  • 2016-09-27 22:04:31
  • 4318

Linux系统环境下关于多进程并发写同一个文件的讨论

Linux系统环境下关于多进程并发写同一个文件的讨论2011-09-18 14:42:19 分类: LINUX 讨论关于并发环境下,多个进程对同一文件写入的问题,我们会涉及到文...
  • baobaoyan
  • baobaoyan
  • 2014-05-20 15:32:43
  • 1080

JAVA多线程之两个线程同时写一个文件

1.多线程    线程是程序执行流的最小单元。是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所...
  • qq_32971807
  • qq_32971807
  • 2016-08-04 09:20:37
  • 7109

Linux下多个进程或线程同时对一个文件进行写操作

Linux下多个进程或线程同时对一个文件进行写操作,如何解决冲突? 使用flock(锁定文件或解除锁定),简单可行! 先介绍一下flock函数吧 头文件 #include 定义...
  • cuiyifang
  • cuiyifang
  • 2013-03-14 13:27:53
  • 3442

多个进程访问同一文件的解决方法

如果多个用户对一个文件进行操作的时候?如何来解决?考虑用文件锁的形式和多路复用的形式 ①文件锁 使用flock(锁定文件或解除锁定)函数 头文件:#include 函数原型:int flock...
  • Eleanor_12
  • Eleanor_12
  • 2016-10-21 22:46:00
  • 2444

进程间通信--两个进程操作同一个文件

a.txt文件内容如下: hello,world。 编写两个不同的可执行程序,名称分别为a和b。在a程序中调用open函数打开a.txt文件,在b程序不可调用open或者fopen。只允许调用re...
  • waldmer
  • waldmer
  • 2015-05-07 22:34:47
  • 1836
    个人资料
    持之以恒
    等级:
    访问量: 23万+
    积分: 3913
    排名: 1万+
    友情链接
    最新评论