18

ここから:UNIXではファイルはアトミックに追加されますか

複数のプロセスが同じファイルを開いてそれに追加する場合を考えてみましょう。O_APPENDは、ファイルの終わりまでシークしてから書き込み操作を開始することがアトミックであることを保証します。したがって、複数のプロセスが同じファイルに追加でき、各書き込みサイズが<= PIPE_BUFである限り、他のプロセスの書き込みを上書きするプロセスはありません。

複数のプロセスを開いて同じファイルに書き込むテストプログラムを作成しました(write(2))。各書き込みサイズが>PIPE_BUF(4k)であることを確認します。プロセスが他の誰かのデータを上書きするインスタンスが表示されることを期待していました。しかし、それは起こりません。さまざまな書き込みサイズでテストしました。それは運だけですか、それともそれが起こらない理由がありますか?私の最終的な目標は、同じファイルに追加する複数のプロセスが書き込みを調整する必要があるかどうかを理解することです。

これが完全なプログラムです。すべてのプロセスはintバッファーを作成し、すべての値をそのバッファーで埋めrank、ファイルを開いて書き込みます。

仕様:OpenSUSE11.364ビットのOpenMPI1.4.3

コンパイル:mpicc -O3 test.c、実行:mpirun -np 8 ./a.out

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

int 
main(int argc, char** argv) {
    int rank, size, i, bufsize = 134217728, fd, status = 0, bytes_written, tmp_bytes_written;
    int* buf;
    char* filename = "/tmp/testfile.out";

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    buf = (int*) malloc (bufsize * sizeof(int));   
    if(buf == NULL) {
        status = -1;
        perror("Could not malloc");
        goto finalize;
    }
    for(i=0; i<bufsize; i++) 
        buf[i] = rank;

    if(-1 == (fd = open(filename, O_APPEND|O_WRONLY, S_IWUSR))) {
        perror("Cant open file");
        status = -1;
        goto end;
        exit(-1);
    }

    bytes_written = 0;
    if(bufsize != (tmp_bytes_written = write(fd, buf, bufsize))) {
        perror("Error during write");
        printf("ret value: %d\n", tmp_bytes_written);
        status = -1;
        goto close;
    }

close:
    if(-1 == close(fd)) {
        perror("Error during close");
        status = -1;
    }
end:
    free(buf);
finalize:
    MPI_Finalize();
    return status;
}
4

3 に答える 3

18

書き込みのアトミシティはPIPE_BUF、パイプとFIFOにのみ適用されます。ファイル書き込みの場合、POSIXは次のように述べています。

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

...これはあなたが自分自身でいることを意味します-異なるUNIXライクは異なる保証を与えます。

于 2012-10-17T21:10:27.830 に答える
16

まず、WindowsのO_APPENDまたは同等のFILE_APPEND_DATAは、最大ファイル範囲(ファイルの「長さ」)の増分が同時ライターではアトミックであり、PIPE_BUFだけでなく任意の量であることを意味します。これはPOSIXによって保証されており、Linux、FreeBSD、OS X、およびWindowsはすべて正しく実装されています。Sambaもそれを正しく実装しますが、v5より前のNFSは、アトミックに追加するワイヤーフォーマット機能がないため、実装していません。したがって、append-onlyでファイルを開くと、NFSが関与していない限り、主要なOSで同時書き込みが互いに引き裂かれることはありません。

ただし、これは、読み取りで書き込みが破損するかどうかについては何も述べていません。その上で、POSIXは、通常のファイルに対するread()およびwrite()のアトミック性について次のように述べています。

以下の関数はすべて、通常のファイルまたはシンボリックリンクを操作するときにPOSIX.1-2008で指定された効果において、相互にアトミックである必要があります...[多くの関数]... read()... write( )... 2つのスレッドがそれぞれこれらの関数のいずれかを呼び出す場合、各呼び出しは、他の呼び出しの指定された効果をすべて表示するか、いずれも表示しないものとします。[ソース]

書き込みは、他の読み取りおよび書き込みに関してシリアル化できます。ファイルデータのread()が(何らかの方法で)データのwrite()の後に発生することが証明できる場合は、呼び出しが異なるプロセスによって行われた場合でも、そのwrite()を反映する必要があります。[ソース]

しかし逆に:

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

これら3つの要件すべてを安全に解釈すると、同じファイル内のエクステントと重複するすべての書き込みを相互にシリアル化し、引き裂かれた書き込みがリーダーに表示されないように読み取る必要があります。

安全性は劣りますが、それでも許可されている解釈は、同じプロセス内のスレッド間で読み取りと書き込みが相互にシリアル化されるだけであり、プロセス間で書き込みが読み取り専用に関してシリアル化されることです(つまり、プロセスですが、プロセス間のI / Oは取得リリースのみです)。

もちろん、標準がこれらのセマンティクスを要求しているからといって、実装が準拠しているわけではありませんが、実際には、ZFSを備えたFreeBSDは完全に動作し、NTFSを備えたごく最近のWindows(10.0.14393)は完全に動作し、ext4を備えた最近のLinuxは、O_DIRECTがオンの場合に正しく動作します。 。主要なOSおよびファイリングシステムが標準にどの程度準拠しているかについて詳しく知りたい場合は、この回答を参照してください。

于 2016-02-07T22:45:35.837 に答える
6

カーネルを掘り下げれば、特定の状況では、あるプロセスwriteが別のプロセスとインターリーブされることは決してないという意味で、運はありません。私はそれを仮定しています:

  • ファイルサイズの制限に達していません
  • テストファイルを作成するファイルシステムを埋めていません
  • ファイルは通常のファイルです(ソケット、パイプ、またはその他のものではありません)
  • ファイルシステムはローカルです
  • バッファは複数の仮想メモリマッピングにまたがっていません(これはmalloc()、連続しているヒープに配置されるedであるため、trueであることがわかっています。
  • write()ビジー状態の間、プロセスが中断、シグナリング、またはトレースされることはありません。
  • ディスクI/Oエラー、RAM障害、またはその他の異常な状態はありません。
  • (多分他の人)

これらすべての仮定が当てはまる場合、使用しているオペレーティングシステムのカーネルがwrite()、次のファイルへの単一のアトミック連続書き込みを使用して、常に単一のシステムコールを実行する場合があります。

それはあなたがこれが常に真実であると期待できるという意味ではありません。次の場合に、それが正しくない可能性があるのはいつかわかりません。

  • プログラムは別のオペレーティングシステムで実行されます
  • ファイルはNFSファイルシステムに移動します
  • プロセスはwrite()進行中にシグナルを受け取りwrite()、部分的な結果を返します(要求されたよりも少ないバイト数)。POSIXが本当にこれを可能にするかどうかはわかりませんが、私は防御的にプログラムします!
  • 等...

したがって、実験では、インターリーブされていない書き込みを信頼できることを証明できません。

于 2012-10-17T21:11:10.480 に答える