web-dev-qa-db-ja.com

複数のプロセスが同じファイルに同時に書き込むのは安全ですか? [CentOs 6、ext4]

複数のスレーブプロセスがUNIXドメインソケットを介して通信し、同時に同じファイルに書き込むシステムを構築しています。私はファイルシステムやこの特定のファイルシステム(ext4)を研究したことはありませんが、ここには何らかの危険があるかもしれません。

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

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

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

注:この質問を投稿してからの私の読書は、以下に投稿された唯一の回答に同意しません。私が読んだことはすべて、私がやりたいことが大丈夫であることを示唆していますが、下の回答者は私がやっていることは安全ではないと主張していますが、記載された危険を識別することはできません。

45
Fixee

POSIX "raw" IO read()、write()、lseek()などのsyscallsを使用している場合、あなたがしていることはまったく問題ないようです。

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

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

26
janneb

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

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

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

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


編集

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

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

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

引用:

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

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

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


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

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


編集2:

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

ブロックサイズがシステムのファイルバッファサイズと正確に一致する場合にのみ、これは機能します!

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

24
Tilo