0

メッセージを受信するたびに発生する MessageReceived イベントを持つチャット セッション クラスがあります。セッション クラスには、セッションを閉じてそれ以上メッセージが受信されないようにするための切断イベントもあります。

    public class Session
    {
        event EventHandler<string> MessageReceived;
        public void Disconnect();
    }

セッションの MessageReceived イベントをサブスクライブし、ハンドラーでメッセージをデコードし、それを使用してアプリケーションを更新します。たとえば、特定のユーザーに関する更新やユーザーの参加に関するメッセージなどをメッセージに含めることができます。

アプリケーションを閉じるには、まず MessageReceived イベントのサブスクライブを解除してから、Disconnect を呼び出します。次に、アプリケーションが使用するすべてのリソースをクリーンアップして破棄します。

よく考えないと、MessageReceived のサブスクライブを解除して Disconnect を呼び出したからといって、これ以上 MessageReceived イベントを発生させることはできないと思うかもしれません。これは明らかにそうではありません。サブスクライブを解除して Disconnect を呼び出す直前に、イベント ハンドラーが既に開始されている可能性は十分にあります。

ここでの問題は、Disconnect を呼び出した後、アプリケーション リソースのクリーンアップと破棄に進むことですが、これらは MessageReceived ハンドラー内で仮想的にアクセスできるリソースと同じであることです。未処理の例外が発生するのを待っています。

切断を呼び出した後、ティアダウンを続行する前に、イベント ハンドラーが再度呼び出されないようにしたいと考えています。

この状況でのベスト プラクティスについて教えてください。できれば、この状況が発生して対処される .NET フレームワークの例を指摘してください。

ありがとうございました

4

2 に答える 2

-1

複数のソースからの刺激を処理する必要があるシステムでこれに対処する標準的な方法の 1 つは、すべての刺激とそのパラメーターをスレッドセーフなキューに集め、1 つの専用スレッドでこれらの項目を処理することです。

そこから、シャットダウンは非常に簡単です。「停止」イベントをキューに入れると、キューを処理しているスレッドが簡単に停止イベントを認識し、キューの参照を停止します。

これは、Windows が UI イベントに使用するモデルです。

たとえば、5 つのネットワーク インターフェイスとそれぞれがパケットを受信する 1 つのスレッドがあり、イベントを処理するエージェントが安全な方法でそれを行うようにしたい場合は、このように処理します。これはあなたが必要としているものには少しやり過ぎですが、より一般的な観点から問題を考えるのに役立ちます.

ここでは、イベント ハンドラーが 1 つのスレッドからのみ起動され、シャットダウンをトリガーするコードがシャットダウンの完了を待つ必要がないことを前提とする 1 つのアイデアを示します。そうでない場合、これは機能しません。とにかく、シャットダウンするには、手動でイベントを発生させ、メッセージが偽のシャットダウン メッセージであることを伝えます。シャットダウンされたことを示すフラグを設定し、イベント ハンドラーを登録解除し、シャットダウン コールを実行します。イベント ハンドラーが 1 つのスレッドでのみ発生すると仮定すると、このスレッドからのみ内部状態をシャットダウンしようとすることが保証されます。

イベントが複数のスレッドから発生する可能性がある場合、これは機能しません。たとえば、UI スレッドがシャットダウンのためにイベントを発生させているが、ソケット受信スレッドが実際のイベントのためにイベントを発生させている場合です。また、シャットダウンを開始するコードが、何らかの理由で実際のシャットダウンが完了するまで待機する必要がある場合、イベントが終了したことを安全に通知するのを待つ方法がないため、これは機能しません。実際のシャットダウン コードをすべてイベント ハンドラー内に移動すれば、問題にはならないかもしれません。

これを処理する別の方法がありますが、これはもう少し複雑です。イベント ハンドラーにいる間は、シャットダウン コードを進行させることはできません。既にシャットダウンを開始している場合は、イベント ハンドラーに入ることができません。

いくつかのロックが必要です。

イベント ハンドラーに入ったら、ロックを取得します。ロックを取得し、シャットダウン フラグが設定されていることがわかった場合は、そのまま戻ってください。それ以外の場合は、まだロックされている間に、イベントを処理します。

シャットダウン コードを入力したら、ロックを取得します。シャットダウンすることを設定します。ロックを解除します。イベント ハンドラーの登録を解除し、クリーンアップを実行します。

シャットダウン コードの実行時にイベントを処理していた場合、シャットダウン コードはイベントが終了するまでロックでブロックされます。

ロックを保持しているシャットダウンコードにいる間にイベントが発生する可能性があります。イベント コードは、ロックを待ってブロックします。シャットダウンフラグが設定されているとマークした後、ロックを解除してから、シャットダウンを開始します。したがって、ロックを解除すると、イベント コードが起動し、シャットダウン コードが実行され続け、イベント コードはシャットダウン フラグが設定されていることを確認し、リソースに触れることなく終了します。

于 2013-03-30T03:45:31.867 に答える