この質問について疑問に思っていたとき、私が設計しているアプリケーションの競合状態について心配していました。
プログラムの1つのコンポーネントによって管理される、ある種の大きな配列またはコレクションがあるとしましょう。そのコンポーネントをMonitorと呼びましょう。その仕事は、コレクションが「ダーティ」であるかどうか、つまり最近変更されたかどうかを定期的にチェックし、変更された場合は、スナップショットをディスクに書き込み(これは、クラッシュが発生した場合にアプリケーションをチェックポイントすることです)、再度クリーンとしてマークすることです。
別のスレッドで実行されている同じプログラムの他のコンポーネントは、モニターのメソッドを呼び出して、配列/コレクションにデータを追加したり、データを変更したりします。これらのメソッドは、コレクションをダーティとしてマークします。
さて、変更メソッドは他のコンポーネントのスレッドで実行されますよね?そして、運が悪ければ、スナップショットがディスクに書き込まれているときに呼び出され、すでに書き込まれているデータを変更し、ダーティフラグを設定すると、その直後にモニターのスレッドが変更を保存せずに設定を解除する可能性があります(それが変更されたとき、すでに要素を過ぎていました)。だから私はきれいとしてマークされている汚れたコレクションを持っています。
しばらくの間、コレクションの一時的なコピーを作成し、それをクリーンにマークしてから、コピーをシリアル化することで問題を解決できるのではないかと思いました。しかし、コピーはアトミックでしょうか。つまり、コピー中にコレクションが変更されないことを確認できますか?
その間、私は次のようなより良い解決策を見つけたと思います
- ディスクへの書き込みを開始する前にロックフラグを設定し、フラグが設定解除されるまでデータ変更メソッドを待機させます
- データ変更メソッドをコレクションに直接ではなく「変更キュー」に書き込み、そのキューのディスク書き込みプロセスを実行するスレッドを使用する
そして、ロックフラグが最善の方法かもしれないと思います。しかし、私はまだ興味があります:可変アトミックをコピーしていますか?
フォローアップ:これはそれ自体の問題になるかもしれませんが、実際にはほとんど同じです。以下の回答によると、私の「ロックフラグ」アプローチも機能しない可能性がありますよね?データ変更メソッドは、「ロックされた」値に設定されているときにロックフラグをチェックし、ロックされていないと判断する可能性があるためです。ですから、本当にこれを正しく行いたいのであれば、ミューテックスのような特別な構造が必要ですよね?
私のフォローアップで彼の非常に有益な答えをくれたエリクソンに称賛を送ります。私は本当にこの2つの質問をするべきだったので、2つの答えを受け入れることができたはずです。彼も投票してください。