0

マルチスレッド アプリケーションをテストするために、VS2010 で MS 単体テストを実行しています。

アプリケーションは を使用しAutoResetEventてスレッドを同期します。これは次のように宣言されます。

private readonly AutoResetEvent captureParsedEvent = new AutoResetEvent(false);

メイン テスト スレッド (ID: 13)

メインのテスト スレッドは、スレッドを起動してキャプチャ ファイルを解析し、次に を呼び出しWaitOne()AutoResetEvent、キャプチャが完了するまでブロックします。

int id = Thread.CurrentThread.ManagedThreadId;
CaptureManager.Instance.StartProcessingPackets();
Trace.WriteLine("[" + id + "]: WAITING ON CaptureParsedEvent");
captureParsedEvent.WaitOne();
Trace.WriteLine("[" + id + "]: WAITING ON CaptureParsedEvent DONE!");

// Analyse parsed capture...

(補足:コードにはもともとcaptureParsedEvent.Reset()afterへの呼び出しがありましたWaitOne()が、この問題を調査しているときにこれを削除しました。私の調査では、これはAutoResetEventオブジェクトには必要ない可能性があると結論付けられたためです。)

解析スレッド (ID: 18)

一方、解析を行っているスレッドは次のAutoResetEventように通知します。

private void InstanceManagerStateChanged(ManagerStateEventArgs ea, object sender)
{
    int id = Thread.CurrentThread.ManagedThreadId;
    switch(ea.CurrentState)
    {
        case ManagerState.ReadPacketsDone:
            Trace.WriteLine("\t[" + id + "]: CaptureParsedEvent SIGNAL");
            captureParsedEvent.Set();
            Trace.WriteLine("\t[" + id + "]: CaptureParsedEvent DONE!");
            break;
    }
}

通常、すべてが正常に動作し、出力ウィンドウに次の予想される出力が表示されます。

[13]: WAITING ON CaptureParsedEvent
    [18]: CaptureParsedEvent SIGNAL
    [18]: CaptureParsedEvent DONE!
[13]: WAITING ON CaptureParsedEvent DONE!

ただし、次の出力が断続的に表示されます。

[13]: WAITING ON CaptureParsedEvent
[13]: WAITING ON CaptureParsedEvent DONE!

キャプチャが実際に解析を終了していないため、これは明らかに問題を引き起こしています。

上記の場所は の唯一の発生であるcaptureParsedEvent.Set();ため、他の誰もイベントを通知していないことがわかります.

いくつかの質問:

  1. Trace.WriteLine()スレッドセーフで、正しい順序でトレースを出力していますか?

  2. この問題は、VS2010 で単体テストを実行しているときにしか見たことがありません。テストが並行して実行され、このシナリオで問題が発生している可能性があるスレッドの使用で何かおかしいことがありますか? 私の理解では、テストは連続して実行されますが、これが正しいかどうかはわかりません。

4

3 に答える 3

1

デフォルトでは、Visual Stufio 2010 はテストを並行して実行しません。テスト設定ファイル (parallelExecutionCount=0) を手動で編集して、これを有効にする必要があります。

あなたが提供したコードを見ると、原因はシグナリングがシングルトン (CaptureManager.Instance) 内で行われるという事実に関連している可能性があります。以前のテストが既に実行されていて、ManagerState が既に完了している場合があります。この仮定を検証するために、テストを単独で実行してみてください。

テストを順番に実行している場合、このような副作用を避けるために、テスト間でシングルトンの状態をリセットする必要がある場合があります。ただし、シングルトンが使用されるすべての場所でこれを行う必要があることに注意してください。このクラスがコードベース全体で頻繁に使用される場合、これは理想的ではないことが判明する可能性があります。

テストを並行して実行している場合、テストの実行時に既知の状態を保証できないため、すべての賭けは無効になります。最善の選択肢は、オブジェクト間の関係を再設計して、グラフをインスタンス化し、副作用なしで実行できるようにすることです。

于 2012-04-01T15:24:15.647 に答える
1

あなたが得ているのは、評価時に、でea.CurrentStateはないという事実が原因であるように思われるManagerState.ReadPacketsDoneため、そのケースステートメント内のコードをスキップしています。ManualResetEvents は自分自身を設定しません。設定した場合、誰にとっても大きな問題になります (そのような問題を抱えている人は聞いたことがありません)。そのため、他の誰もイベントを設定しないようにする必要があります。

質問 1:Trace.WriteLine()はスレッド セーフですが、writeline を呼び出すスレッドが複数ある場合、それらの呼び出しが順番に実行される保証はありません。ただし、あなたの場合、SIGNALメッセージDONEは同じスレッドで実行されるため、次々に書き込まれます。さらに重要なことは、正しい状態を取得した場合、手動リセット イベントを設定する前に発生するため、少なくともCaptureParsedEvent SIGNAL前に出力されることです。信号を送った後は、とWAITING ON CaptureParsedEvent DONEのプリントの順序は保証されません。WAITING ON CaptureParsedEvent DONECaptureParsedEvent DONE

別のスレッドが同時に書き込みを行っている場合、その間に何かを書き込むことができます。しかし、すでに述べたように、それea.CurrentStateManagerState.ReadPacketsDone.

質問 2: 並行性を扱っている場合、常に「何かおかしい」ことが起こっているか、並行プログラミングで通常得られるのと同じくらい「おかしい」ことがあります。慎重にスレッド化する必要があります。繰り返しますが、あなたの問題は同時実行性に起因するとは思いません。単に正しいケースを処理していないように見えるか、他の誰かが同じManualResetEvent.

于 2012-03-30T04:30:59.053 に答える
0

問題を解決しました。

コードが処理していた各パケットについて、InstanceManagerStateChanged()デリゲートのリストにコールバックを追加していたことがわかります。

CaptureManager.Instance.ManagerStateChanged += InstanceManagerStateChanged;

しかし、正しく購読を解除していませんでした。つまり、前のパケットから通知を受け取っていた可能性があります。

次のパケットを処理する前にサブスクライブを解除すると、この問題が修正されました。

CaptureManager.Instance.ManagerStateChanged -= InstanceManagerStateChanged;
于 2012-04-16T02:11:40.003 に答える