write的多進程/線程安全性

   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入文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章