0

イベントがトリガーされるのを待たなければなりません。私の最初の解決策はAutoResetEventandを使用することでしたが、待機タイムアウトが終了した直後にWaitOne()イベントが常にトリガーされました。そこで、以下のアプローチに戻りましたが、それでも同じ問題があります。タイムアウトが終了してから2〜3秒後に、タイムアウトが何であったかに関係なく、イベントがトリガーされます。

_wait = true;
_delayedResponse = null;

var thread = new Thread(delegate
{
        while (_wait)
        {
           Thread.Sleep(500);
           if (_delayedResponse != null)
               return;
        }
});

thread.Start();
var received = thread.Join(_responseTimeout);
_wait = false;

if (!received)
    throw new TimeoutException(
        "Timeout for waiting for response reached.");

return _delayedResponse;

イベントハンドラコードは次のとおりです。

private void OnResponseArrived(object sender, ResponseEventArgs args)
{
    _delayedResponse = args.VerificationResponse;
}

イベント自体は、上記の関数を呼び出す別の関数からトリガーされます。基本的には次のようになります。

var result = DoStuff(); // Library function that is responsible for the event 
if (result.Status == Status.Wait)
   Wait(); // Function above

誰かがこの問題の原因と私がそれを解決する方法を知っていますか?

編集:もう関係ありません。時間内に他の解決策が見つからなかったため、OnResponseArrivedイベントを転送しました。

4

2 に答える 2

2

Thread.Joinブロッキング呼び出しです-呼び出しているスレッドが他の作業を実行するのを停止します。私の推測では、バックグラウンドスレッドでイベントを待っていますが、イベントを発生させるコードは、投稿したコードが実行されているのと同じスレッドで実行されています。

呼び出すthread.Joinことにより、処理を実行しているはずのスレッドをブロックしています。したがって、タイムアウトが期限切れになるのを待ちます...その後、投稿されたコードがどの方法で完了しても...その後、処理が実際に行われ、ResponseArrivedイベントが発生します。

残りのコードを投稿すると便利ですが、解決策の要点はResponseArrived、バックグラウンドスレッドで実際の作業(イベントを発生させるコード)を実行し、投稿したコードから余分なスレッドを削除することです。 。

コメントに応じて編集...

2つのコードを同期するために、を使用できますAutoResetEventThread.Sleepおよび他のコードを使用する代わりに、次のようなものを試してください。

// create an un-signalled AutoResetEvent
AutoResetEvent _waitForResponse = new AutoResetEvent(false);

void YourNewWorkerMethod()
{
    _delayedResponse = null;
    var result = DoStuff();

    // this causes the current thread to wait for the AutoResetEvent to be signalled
    // ... the parameter is a timeout value in milliseconds
    if (!_waitForResponse.WaitOne(5000))
        throw new TimeOutException();

    return _delayedResponse;
}


private void OnResponseArrived(object sender, ResponseEventArgs args)
{
    _delayedResponse = args.VerificationResponse;
    _waitForResponse.Set();  // this signals the waiting thread to continue...
}

使い終わったら、廃棄する必要があることに注意してくださいAutoResetEvent

于 2011-01-27T12:40:48.533 に答える
2

さて、あなたがする必要がある最初のことは、それがDoStuff実際にバックグラウンドスレッドで機能することを確認することです。

それが正しければ、現在のコードの記述方法では、2番目のスレッドを生成する必要はなく、1行下に結合するだけで、次のようになります(テストとして)。

// handler needs to be attached before starting
library.ResponseReceived += OnResponseReceived;

// call the method
var result = library.DoStuff();

// poll and sleep, but 10 times max (5s)
int watchdog = 10;
while (_delayedResponse == null && watchdog-- > 0)
   Thread.Sleep(500);

// detach handler - always clean up after yourself
library.ResponseReceived -= OnResponseReceived;

Console.WriteLine(_delayedResponse != null);

これが機能し、WinFormsアプリをプログラミングしている場合は、すべてをバックグラウンドスレッドで実行し、終了時にUIに通知することを検討する必要があります。もちろん、サポートが必要な場合は、詳細を提供する必要があります。

于 2011-01-27T12:52:18.787 に答える