2

私はこのコードをCで書きました:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void random_seed(){
    struct timeval tim;
    gettimeofday(&tim, NULL);
    double t1=tim.tv_sec+(tim.tv_usec/1000000.0);
    srand (t1);
}

void main(){
    FILE *f;
    int i;
    int size=100;
    char *buf=(char*)malloc(size);

    f = fopen("output.txt", "a");
    setvbuf (f, buf, _IOFBF, size);
    random_seed();

    for(i=0; i<200; i++){
          fprintf(f, "[ xx - %d - 012345678901234567890123456789 - %d]\n", rand()%10, getpid());
          fflush(f);
    }

    fclose(f);
    free(buf);
}

このコードは、ファイルを追加モードで開き、文字列を200回添付します。完全な文字列を含めることができるサイズ100のbufを設定しました。次に、次のbashスクリプトを使用して、このコードを実行するマルチプロセスを作成しました。

#!/bin/bash

gcc source.c
rm output.txt

for i in `seq 1 100`;
do
    ./a.out &
done

O_APPENDフラグを使用してファイルを開くと、各書き込みの前にファイルオフセットがファイルの最後に設定され、完全にバッファリングされたストリームを使用していることを読んだため、出力で文字列が混同されることはないと予想しました。しかし、私は各プロセスの最初の行が次のように混合されていることを取得しました:

[ xx - [ xx - 7 - 012345678901234567890123456789 - 22545]

そして数行後

2 - 012345678901234567890123456789 - 22589]

rand関数を呼び出すために書き込みが中断されたようです。

それで...なぜこれらの線が現れるのですか?これを防ぐ唯一の方法は、ファイルロックを使用することです...追加モードのみを使用している場合でも?

前もって感謝します!

4

2 に答える 2

2

何らかの形式の同時実行制御を自分で実装する必要があります。POSIXは、複数のプロセスからの同時書き込みに関して保証を行いません。パイプについてはある程度の保証がありますが、異なるプロセスから書き込まれた通常のファイルについては保証されません。

POSIXwrite()の引用:

POSIX.1-2008のこのボリュームは、複数のプロセスからのファイルへの同時書き込みの動作を指定していません。アプリケーションは、何らかの形式の同時実行制御を使用する必要があります。

(理論的根拠のセクションの終わりにあります。)

于 2012-01-22T11:27:10.020 に答える
0

ファイルを完全バッファモードで開きます。つまり、出力のすべての行が最初にバッファに入り、バッファがオーバーフローすると、不完全な行が含まれているかどうかに関係なく、ファイルにフラッシュされます。これにより、同じファイルに同時に書き込む異なるプロセスからの出力のチャンクがインターリーブされます。

簡単な修正は、ファイルを行バッファモードで開いて_IOLBF、バッファが完全な行ごとにフラッシュされるようにすることです。バッファサイズが少なくとも最長の行と同じ大きさであることを確認してください。そうしないと、不完全な行が書き込まれることになります。バッファは通常、1回のwrite()システムコールでフラッシュされるため、異なるプロセスからの行が相互にインターリーブすることはありません。

write()ただし、システムコールがさまざまなファイルシステムに対してアトミックであるという保証はありませんがwrite()、続行する前にカーネル内のファイル記述子をミューテックスでロックするため、通常は期待どおりに機能します。

于 2012-01-22T14:00:34.243 に答える