61

複数のスレーブ プロセスが UNIX ドメイン ソケット経由で通信し、同時に同じファイルに書き込みを行うシステムを構築しています。私はファイルシステムやこの特定のファイルシステム (ext4) について調べたことはありませんが、ここには危険が潜んでいるように感じます。

各プロセスは、出力ファイルのばらばらなサブセットに書き込みます (つまり、書き込まれるブロックに重複はありません)。たとえばP1、ファイルの最初の 50% にのみ書き込み、次の 50% にのみ書き込みますP2。またはP1、奇数ブロックのみをP2書き込み、偶数ブロックを書き込みます。

ロックを使用せずに同じファイルに (別々のスレッドで同時に実行して) 書き込むことP1は安全ですか? P2言い換えれば、ファイルシステムはある種のロックを暗黙的に強制しますか?

注:残念ながら、複数のファイルを出力して後で結合する自由はありません。

注:この質問を投稿してからの私の読書は、以下に投稿された唯一の回答と一致しません。私が読んだものはすべて、私がやりたいことは問題ないことを示唆していますが、以下の回答者は、私がしていることは安全ではないと主張していますが、説明されている危険性を認識できません.

4

2 に答える 2

37

read()、write()、lseek() などの POSIX の「生の」IO syscall を使用していれば、あなたがしていることはまったく問題ないように見えます。

C stdio (fread()、fwrite() およびその仲間) または独自のユーザー空間バッファリングを持つ他の言語ランタイム ライブラリを使用する場合、「Tilo」による回答は関連性があります。制御できない範囲で、異なるプロセスが互いのデータを上書きする可能性があります。

OS ロックに関しては、サイズ PIPE_BUF 未満の書き込みまたは読み取りが一部の特殊ファイル (パイプおよび FIFO) に対してアトミックであるという POSIX 状態が示されていますが、通常のファイルに対してはそのような保証はありません。実際には、ページ内の IO はアトミックである可能性が高いと思いますが、そのような保証はありません。OS は、独自の内部データ構造を保護するために必要な範囲でのみ、内部でロックを行います。ファイル ロックやその他のプロセス間通信メカニズムを使用して、ファイルへのアクセスをシリアル化できます。ただし、これはすべて、ファイルの同じ領域に対して複数のプロセスが IO を実行している場合にのみ関係します。あなたの場合、プロセスは IO を実行してファイルのセクションを分離しているため、これは問題ではなく、問題ありません。

于 2011-10-25T16:47:19.497 に答える
33

いいえ、一般的にこれを行うのは安全ではありません!

プロセスごとに排他的な書き込みロックを取得する必要があります。これは、1つのプロセスがファイルに書き込んでいる間、他のすべてのプロセスが待機する必要があることを意味します。I/ Oを集中的に使用するプロセスが多いほど、待機時間が長くなります。

プロセスごとに1つの出力ファイルを用意し、それらのファイルを行の先頭にタイムスタンプとプロセスIDを付けてフォーマットして、後でそれらの出力ファイルをオフラインでマージおよびソートできるようにすることをお勧めします。

ヒント:Webサーバーのログファイルのファイル形式を確認してください。これらは行の先頭にタイムスタンプが付いているため、後で組み合わせて並べ替えることができます。


編集

UNIXプロセスは、ファイルを開くときに特定の/固定のバッファサイズ(たとえば、4096バイト)を使用して、ディスク上のファイルとの間でデータを転送します。書き込みバッファがいっぱいになると、プロセスはそれをディスクにフラッシュします。つまり、完全な完全なバッファをディスクに書き込みます。ここで、バッファがいっぱいになったときに発生していることに注意してください。-行末があるときではありません!つまり、行指向のテキストデータをファイルに書き込む単一のプロセスの場合でも、これらの行は通常、バッファがフラッシュされるときに途中で切断されます。最後に、書き込み後にファイルを閉じるときに、ファイルに完全な行が含まれていると見なすことができます。

したがって、プロセスがバッファをフラッシュすることを決定したタイミングに応じて、ファイルへの書き込みは異なります。たとえば、順序は決定論的/予測可能ではありません。バッファがファイルにフラッシュされる場合、完全な行のみを書き込むとは限りません。 -たとえば、通常は部分的な行を書き込むため、複数のプロセスが同期せずにバッファをフラッシュすると、出力が台無しになります。

ウィキペディアでこの記事を確認してください:http://en.wikipedia.org/wiki/File_locking#File_locking_in_UNIX

引用:

Unixオペレーティングシステム(LinuxおよびAppleのMac OS X、Darwinと呼ばれることもあります)は通常、開いているファイルや実行中のプログラムを自動的にロックしません。さまざまな種類のUnixでいくつかの種類のファイルロックメカニズムが利用可能であり、多くのオペレーティングシステムは互換性のために複数の種類をサポートしています。最も一般的な2つのメカニズムは、fcntl(2)とflock(2)です。3番目のそのようなメカニズムはlockf(3)であり、これは別個のものであるか、最初の2つのプリミティブのいずれかを使用して実装される場合があります。

プロセスを同期し、一度に1つだけがファイルに書き込めるようにするために、flockまたはMutexesのいずれかを使用する必要があります。

前に述べたように、プロセスごとに1つの出力ファイルを作成し、後で必要に応じてそれらのファイルを結合する(オフライン)方が、おそらくより速く、より簡単で、より簡単です。このアプローチは、たとえば、複数のスレッドから複数のファイルにログを記録する必要がある一部のWebサーバーで使用されます。また、異なるスレッドがすべて高性能であることを確認する必要があります(たとえば、ファイルで互いに待機する必要はありません)。ロック)。


関連する投稿は次のとおりです:(MarkByerの回答を確認してください!受け入れられた回答は正しくない/関連性がありません。)

>>を使用して、複数の並列プロセスの出力を1つのファイルにパイプするのは安全ですか?


編集2:

コメントで、異なるプロセスから同じファイルに固定サイズのバイナリデータブロックを書き込みたいとおっしゃいました。

ブロックサイズがシステムのファイルバッファサイズとまったく同じである場合にのみ、これは機能します。

固定ブロック長がシステムのファイルバッファサイズと正確に一致していることを確認してください。そうしないと、完了していない行の場合と同じ状況になります。たとえば、16kブロックを使用し、システムが4kブロックを使用する場合、一般に、ファイルには一見ランダムな順序で4kブロックが表示されます。同じプロセスから常に4ブロックが連続して表示される保証はありません。

于 2011-10-20T22:23:49.160 に答える