4

私たちの(WindowsネイティブC ++)アプリは、スレッド化されたオブジェクトとマネージャーで構成されています。それはかなりよく書かれており、マネージャーオブジェクトがミニオンのライフサイクルを制御しているのを見るデザインです。さまざまなオブジェクトがイベントをディスパッチおよび受信します。一部のイベントはWindowsからのものであり、一部は自家製です。

一般に、スレッドの相互運用性を十分に認識している必要があるため、Win32のクリティカルセクションやセマフォなどを使用した手動の同期手法を使用します。ただし、イベントハンドラーの再入可能性などが原因で、シャットダウン中にスレッドのデッドロックが発生することがあります。

中央コントローラーからシャットダウンイベントに登録し、それに応じて実行動作を変更するすべてのオブジェクトのように、これを開発しやすくするために実装できる適切なアプリシャットダウン戦略があるかどうか疑問に思います。これはあまりにも素朴ですか、それとももろいですか?

Microsoftの並列パターンライブラリなどを使用するようにアプリ全体を書き直すことを規定していない戦略を希望します。;-)

ありがとう。

編集:

多くのスレッドとイベントが常に発生している複雑なアプリでオブジェクトのライフサイクルを制御する方法を求めていると思います。Giovanniの提案は明白なものですが(私たち自身の手作業で)、アクティブオブジェクトを正しい順序でクリーンにシャットダウンするには、さまざまな既製の戦略またはフレームワークが必要であると私は確信しています。たとえば、C ++アプリをIoCパラダイムに基づいて作成する場合は、独自のコンテナーを開発する代わりに、PocoCapsuleを使用できます。アプリでオブジェクトのライフサイクルを制御するのに似たものはありますか?

4

3 に答える 3

3

これは、「マルチスレッドアプリケーションでデッドロックを回避するにはどうすればよいですか?」というより一般的な質問の特殊なケースのようです。

そして、その答えは、いつものように、スレッドが一度に複数のロックを取得する必要があるときはいつでも、すべてが同じ順序でロックを取得することを確認し、すべてのスレッドが有限でロックを解放することを確認することです。時間の長さ。このルールは、シャットダウン時に他の時間と同じように適用されます。それ以下のものは十分ではありません。これ以上何も必要ありません。(関連する議論についてはここを参照してください)

これを行う最善の方法については...(可能であれば)最善の方法は、プログラムを可能な限り単純化し、支援できる場合は一度に複数のロックを保持しないようにすることです。

一度に複数のロックを絶対に保持する必要がある場合は、プログラムを検証して、複数のロックを保持するすべてのスレッドがそれらを同じ順序でロックすることを確認する必要があります。helgrindやIntelスレッドチェッカーなどのプログラムこれには役立ちますが、多くの場合、コードがこの制約を満たしていることを証明するまで、コードを単に目で確認することになります。また、デッドロックを簡単に再現できる場合は、(デバッガーを使用して)各デッドロックスレッドのスタックトレースを調べることができます。これにより、デッドロックスレッドが永久にブロックされている場所が示され、その情報を使用して開始できます。コード内のロック順序の不整合がどこにあるかを把握するため。はい、それは大きな苦痛ですが、(一度に複数のロックを保持することを避ける以外に)それを回避する良い方法はないと思います。:(

于 2011-06-27T23:55:17.447 に答える
1

考えられる一般的な戦略の 1 つは、「シャットダウンしています」イベントをすべてのマネージャーに送信することです。これにより、マネージャーは次の 3 つのいずれかを実行します (イベント ハンドラーの実行時間と、イベント ハンドラー間の待機時間に応じて)。ユーザーがシャットダウンを開始し、アプリが実際に終了します)。

1) 新しいイベントの受け入れを停止し、「シャットダウンしています」イベントの前に受信したすべてのイベントのハンドラーを実行します。デッドロックを回避するには、他のイベント ハンドラーの完了に重要なイベントを受け入れる必要がある場合があります。これらは、イベントのフラグまたはイベントのタイプ (たとえば) によって通知できます。そのようなイベントがある場合は、それらのアクションがイベント ハンドラーを介して実行されないように、コードを再構築することも検討する必要があります (従属イベントは、通常の操作でもデッドロックを起こしやすいためです)。

2) 新しいイベントの受け入れを停止し、ハンドラーが現在実行中のイベントの後に受信したすべてのイベントを破棄します。この場合にも、依存イベントに関する同様のコメントが適用されます。

3) 現在実行中のイベントを ( と同様の関数で) 中断し、boost::thread::interrupt()それ以上イベントを実行しません。これには、ハンドラー コードが例外に対して安全である必要があり (リソース リークが気になる場合は、既に安全になっている必要があります)、かなり定期的に中断ポイントに入る必要がありますが、これによりレイテンシが最小限に抑えられます。

もちろん、各マネージャーの特定の待ち時間とデータ破損の要件に応じて、これら 3 つの戦略を組み合わせることもできます。

于 2011-06-27T23:28:37.187 に答える
1

一般的な方法として、アトミック ブール値を使用して「シャットダウン中」を示し、すべてのスレッドがこのブール値をチェックしてから、各ロックの取得、各イベントの処理などを行います。より詳細な質問をしない限り、より詳細な回答はできません。 .

于 2011-06-27T07:13:46.747 に答える