write的多进程/线程安全性

来源:互联网 发布:淘宝不能用网银支付 编辑:程序博客网 时间:2024/06/15 17:42

   write系统调用将指定的内容写入文件中,但是当多个进程/线程同时write一个文件时是会出现写覆盖的情形。

每个进程都有自己的缓冲区,write首先写入该缓冲区,系统flush后才将缓冲区内容写入文件,从而导致了多个进程之间的写操作是互不可见的,可能出现写覆盖。

程序验证:

#include<sys/types.h>#include<stdio.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<sys/wait.h>#include<string.h>int main(){    int fd=open("1.txt",O_RDWR|O_CREAT,S_IRWXU);    pid_t pid[2];//开启2个子进程    if((pid[0]=fork())<0)        printf("fork error\n");    else if(pid[0]==0){        char* buf="00000 00000\n";//子进程1写入文件的内容        for(int i=0;i<5;i++){             if(write(fd,buf,strlen(buf))<strlen(buf))//写入的字数不够情况忽略                 printf("pid[0] write less\n");        }    }    else{        if((pid[1]=fork())<0)            printf("fork 2 error\n");        else if(pid[1]==0){            char* buf="11111 11111 11111\n";            for(int i=0;i<5;i++)                if(write(fd,buf,strlen(buf))<strlen(buf))                    printf("pid[1] write less\n");        }        else{            char* buf="xxxxx\n";            for(int i=0;i<5;i++)                if(write(fd,buf,strlen(buf))<strlen(buf))                    printf("parent write less\n");            waitpid(pid[0],NULL,0);            waitpid(pid[1],NULL,0);        }    }    return 0;}
文件内容:

00000 xxxxx
xxxxx
xxxxx
xxxxx
00000
00000 00000
00000 00000
11111 11111 11111
11111 11111 11111
11111 11111 11111
11111 11111 11111
11111 11111 11111
11111 11111
11111 11111 11111
  从文件内容来看,已经出现了写覆盖的情形。所以write是非进程/线程安全的。

 如果在打开文件加入O_APPEND标志时,文件内容如下:

xxxxx
xxxxx
xxxxx
xxxxx
xxxxx
00000 00000
11111 11111 11111
00000 00000
11111 11111 11111
00000 00000
11111 11111 11111
00000 00000
11111 11111 11111
00000 00000
11111 11111 11111

     这时候没有存在写覆盖的情形,只是文件写的顺序有交叉而已。但是注意O_APPEND的语义中有这么一点内容:

 O_APPEND may lead to corrupted files on NFS file systems if more than one process appends data to a file at once.This is because NFS does not support appending to a file, so the client kernel has to simulate it, which can't be done  without a race condition

    但是在apue的59页说了O_APPEND是一个原子操作。这里有点疑惑?如果线程A调用write欲写入文件F的字数是100,但是写了80个字write就反回了,线程B此时立刻写入文件F也20个字节,此时本来属于A的那20个字节现在是线程B的?这种情况可能比较少见,具体的说明可以参见这里,最后得出的结论是即使O_APPEND也可能出现多个写交错的情形。

     通常在日志系统中,开启一个专门的进程/线程进行文件的写操作,其他进程/线程充当生产者将内容传递给专门写的进程/线程负责write入文件。

0 0