Windows ベースの OS では、etc を使用してファイルを頻繁に読み書きする可能性のあるいくつかの異なるプロセスがあると仮定するとfopen/fopen_s/fwrite
、そのような場合、データ競合を考慮する必要がありますか、または OS がこれを自動的に処理してファイル残りの fopen 試行は失敗しますが、いつでもここで単一のプロセスによってのみ開く/更新できますか? そして、この件に関して Linux ベースの OS はどうですか?
3 に答える
Windowsでは、ファイルを開く方法によって異なります。
の場合との場合uStyle
のパラメータのいくつかの可能な値を参照してください。OpenFile
dwShareMode
CreateFile
OpenFile
使用する方が良いですが、これは非推奨のようなものであることに注意してくださいCreateFile
。
複数のスレッドから同じファイルを同時に開かないように注意する必要があります-ファイルを複数回開くことは完全に可能であり、OSは、ファイルを開いているモードに応じて、期待どおりに動作する場合と動作しない場合があります-たとえば、新しいファイルを作成すると、間違いなく2つの異なるファイルが作成されます(一方は、もう一方のスレッドによって削除されたため、閉じると消えます)。ルールはかなり複雑で、最悪の部分は、特別な注意を払わないと、「同じファイルへの出力が混同」されることです。そのため、2つのスレッドから行または行の一部が混ざります。
FILE *
OSが同じファイルを2回開くことを停止した場合でも、「戻ってきた」の結果に対処する必要がありますNULL
。だったらどうしようか?戻って再試行するか、失敗するか、または?
これらのファイルに対して何をしているのかよく説明されていないため、この問題を解決する方法について適切な提案をすることができるかどうかはわかりません。頭に浮かぶいくつかの異なることがあります:
- ファイル名の「レジスタ」と、ファイルを開くために保持する必要のある各ファイルのミューテックスを保持します。
- 単一の「ファイルスレッド」を使用してファイルのデータの読み取り/書き込みを行い、「このファイルをファイルaa.txtに書き込みたい」というキューに入れて、ワーカーに書き込みをさせます。
- 下位レベルのファイルシステムコールを使用し、ファイルへの「排他的」アクセスを使用し、衝突の場合のある種の「バックオフ」動作を使用します。
問題を解決する方法は他にもたくさんあると思います。実際には、何をしようとしているかによって異なります。
多分。異なるプロセス (スレッドではなく) について話している場合、スレッドに適用される従来のデータ競合条件は適用されません。ただし (ここでは Unix と Windows の間に違いはありません):
単一の
write
/WriteFile
操作はアトミックになります。(Windows については 100% 確信が持てませんが、それ以外の場合は想像できません。) ただし、iostream や古いFILE*
関数を使用している場合、それらの操作がいつ行われるかを直接制御することはできません。通常、これらはストリームのバッファがいっぱいになったときにのみ発生します。バッファーが十分な大きさであることを確認し、各出力後に明示的にフラッシュする必要があります。(妥当な長さ、たとえば最大 80 文字の行を出力している場合、バッファが完全な行を保持することは安全な賭けです。この場合、std::endl
iostreams で行を終了するために使用するだけです。C スタイルの関数の場合、setvbuf( stream, NULL, _IOLBF, 0 )
最初の出力の前に呼び出す必要があります。プロセスで開いている各ファイルには、ファイルのどこに書き込むかという独自のアイデアと、ファイルの終わりがどこにあるかという独自のアイデアがあります。
std::ios_base::app
すべての書き込みをファイルの最後まで行いたい場合は、C++ または C の "a" で ファイルを開く必要があります。/std::ios_base::out
だけ"w"
では十分ではありません。(もちろん、juststd::ios_base::out
または "w" を使用すると、ファイルは開いたときに切り捨てられます。いくつかの異なるプロセスでファイルを切り捨てると、データが失われる可能性があります。)他のプロセスが書き込んでいるファイルを読み取る場合: ファイルの終わりに到達すると、ストリームまたは
FILE
エラー状態になり、他のプロセスがデータを追加している場合でも、それ以上読み取ろうとしません。C では、clearerr
これを元に戻す必要がありますが (私はそう思います)、次に何が起こるかは明確ではありません。C++ では、ストリーム内のエラーをクリアしても、それ以降の読み取りですぐにファイルの終わりが発生しないとは限りません。どちらの場合も、最も安全な方法は、各読み取りの前にどこにいたかを覚えておくことです。読み取りに失敗した場合は、ファイルを閉じてから再度開き、どこにいたかを探して、そこから読み取りを開始します。すべての書き込みがアトミックである限り (上記を参照)、ランダムアクセス、ファイルの最後以外への書き込みも機能します。常に一貫した状態を取得する必要があります。ただし、書き込み内容が読み取り内容に依存し、他のプロセスが同様のことを行っている場合は、iostream/
FILE*
レベルでは利用できないファイル ロックが必要になります。