複数プロセスからの書き込み - file tableとcurrent offset

同時に複数プロセスから書き込むとファイルが壊れるというが、壊れるというのはどういうことか。

f:id:kotaroito2002:20130929144419p:plain

出典: Advanced Programing in the Unix Environment - Figure3.7

異なるプロセスから同じファイルをopenすると、異なるfile tableエントリー(current file offsetを保持する)が生成される、というのがUNIXにおける仕様とのこと。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "error.h"

#define BUFFSIZE 4096

int main(int argc, char* argv[])
{
    int fd;
    char buff[BUFFSIZE];
    int i;

    fd = open("/tmp/kotaro", (O_WRONLY | O_CREAT));
    for (i = 0; i < 1000000; i++ ) {
        sprintf(buff, "%d\r\n", getpid());
        write(fd, buff, strlen(buff)); 
    }
    close(fd);
}

自身のpidを100万回書き込むという単純なプログラムだが、これを同時に実行してみた結果は以下の通り。

$ cat /tmp/kotaro | sort | uniq -c
263710 79026
736290 79027

全体行数は100万だが、2つのpid(79026と79027)が書き込まれていることがわかる。

ただし、O_APPENDフラグをつけると事情が異なる。これが付いているとwrite(2)実行時には、file末尾までseekし、書き込むまでがatomicになるので、同時に追記書き込みしても漏れることはない。

まとめ

同じファイルを別プロセスからopenすると、offsetを管理するfile tableエントリーは別々につくられるので気をつける。