0

コントロールは 2 つのワーカー スレッドによってアクセスされます。最初のスレッドがコントロールでの作業を完了する前に 2 番目のスレッドがアクセスされます。2 番目のスレッド (9) は InvokeRequired == false を取得し、最初のスレッド (17) は子コントロールで .Refresh を呼び出すときに例外を取得します。

これは予想される動作ですか?スレッドがコントロールの InvokeRequired を true/false と見なす正確な原因は何ですか?
そして最後に、良い解決策は何でしょうか..すべてのinvokeステートメントをロックし、代わりに別のメソッドを呼び出すようにします(明らかにデッドロックを回避するため)?

private void OnHistoryUpdate(object sender)
{
    Console.WriteLine("<< Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId );

    if (this.InvokeRequired)
        this.Invoke(new Action<object>(OnHistoryUpdate), sender);  

    LoadTimeSeries(this.Interval);
    Console.WriteLine(">> Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId);

}

出力:

<< Invoke? True Thread: 17
<< Invoke? False Thread:  9
>> Invoke? False Thread:  9
4

2 に答える 2

1

コードはコントロールを 2 回更新します。

  • への呼び出しを使用してInvoke、別の呼び出しを に委任しOnHistoryUpdateます。Invoke実行を UI スレッドにマーシャリングするため、これは安全です。
  • への呼び出し後InvokeInvoke同期的に実行され、コードが返されると、コードがLoadTimeSeries2回目に呼び出されますが、今回は安全ではありません(InvokeRequired再度チェックしません)。

BeginInvoke以下のようにメソッドを変更し、ワーカー スレッドがブロックされないように代わりに使用することも検討します。

private void OnHistoryUpdate(object sender)
{
    Console.WriteLine("<< Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId );

    if (this.InvokeRequired)
        this.Invoke(new Action<object>(OnHistoryUpdate), sender);
    else  
        LoadTimeSeries(this.Interval);

    Console.WriteLine(">> Invoke? " + this.InvokeRequired   + " " + Thread.CurrentThread.ManagedThreadId);    
}
于 2013-02-21T04:26:13.853 に答える
0

Invoke を使用せずにスレッドからの呼び出しを必要とするコントロールで Refresh を呼び出すと、例外が発生することが予想されます。これを行わないことを確認してください。問題ありません。必要なのはこれだけです。

于 2013-02-21T04:28:00.697 に答える