11

同じミューテックスを共有する2つのプロセス(A、B)があります(WaitForSingleObject / ReleaseMutex呼び出しを使用)。すべて正常に動作しますが、プロセスAがクラッシュすると、プロセスBは順調にハミングします。プロセスAを再開すると、デッドロックが発生します。

詳細な調査により、プロセスAがクラッシュした後、プロセスBがReleaseMutex()を2回正常に呼び出すことができることがわかりました。

私の解釈:プロセスAがクラッシュした後も、ミューテックスはロックされたままですが、ミューテックスの所有権はプロセスBにすぐに移ります(これはバグです)。そのため、WaitForSingleObject(WAIT_OBJECT_0を返す)とReleaseMutex(TRUEを返す)を呼び出して、楽しくハミングしています。

プロセスAのクラッシュによってミューテックスが解放されるように、ミューテックスと同様の名前付き同期プリミティブを使用することは可能ですか?

1つの解決策は、SEHを使用してクラッシュをキャッチし、ミューテックスを解放することですが、プロセスのクラッシュ時にそのようにデッドロックしない堅牢なプリミティブがWindowsにあることを本当に望んでいます。

4

2 に答える 2

29

Windows でミューテックスがどのように機能するかについて、ここで行う必要があるいくつかの基本的な前提を次に示します。

  • ミューテックスは、参照カウントされるオペレーティング システム オブジェクトです。ミューテックスの最後のハンドルが閉じられるまで消えません
  • プロセスの終了時に閉じられていないハンドルは、オペレーティング システムによって閉じられ、参照カウントが減少します。
  • ミューテックスは再入可能であり、同じスレッドのミューテックスで WaitForSingleObject を呼び出すと成功し、同数の ReleaseMutex 呼び出しでバランスをとる必要があります
  • 所有されているミューテックスは、それを所有するスレッドが ReleaseMutex を呼び出さずに終了すると、放棄されます。この状態のミューテックスで WaitForSingleObject を呼び出すと、WAIT_ABANDONED エラー リターン コードが生成されます。
  • オペレーティング システムのバグではありません。

したがって、観察したことから、これから結論を引き出すことができます。A がクラッシュしてもミューテックスには何も起こりませんが、B にはまだハンドルがあります。A がクラッシュしたことを B が認識できる唯一の方法は、A がミューテックスを所有している間に A がクラッシュした場合です。そのオッズは非常に低く、B がデッドロックするため、簡単に観察できます。はるかに可能性が高いのは、B が完全に妨げられていないため、B が喜んでモーターを始動することです。他の誰もミューテックスを取得することはありません。

さらに、A が再起動したときのデッドロックは、すでにわかっていることを証明します。B は、何らかの理由でミューテックスを永続的に所有しています。おそらく、ミューテックスを再帰的に取得したためです。これは、ReleaseMutex を 2 回呼び出す必要があることに気付いたからです。これは修正が必要なバグです。

兄弟プロセスのクラッシュから身を守る必要があり、そのための明示的なコードを記述する必要があります。兄弟で OpenProcess を呼び出して、プロセス オブジェクトのハンドルを取得します。プロセスが終了すると、ハンドルに対する WaitForSingleObject 呼び出しが完了します。

于 2013-02-20T18:10:39.690 に答える
11

ミューテックスを保持しているプロセスがクラッシュすると、そのミューテックスは放棄されます。待機関数から返されたこの状態をどのように処理するかは、他のアプリケーション次第です。

戻ってきた場合WAIT_ABANDONEDは、すべてが問題ないかのように続行するか (おそらく現在の動作)、または「データが不安定になる可能性があるため、注意して続行する」ことができます。所有権が別のプロセスに自動的に渡されることはありません。

于 2013-02-20T17:25:55.727 に答える