0

一个控件由两个工作线程访问,第二个工作线程在第一个工作线程完成它对控件的工作之前。第二个线程 (9) 获取 InvokeRequired == false,然后第一个线程 (17) 在子控件上调用 .Refresh 时获取异常。

这是预期的行为吗?究竟是什么导致线程将控件的 InvokeRequired 视为真/假?
最后,什么是一个好的解决方案。在所有调用语句上加一个锁,并让它们调用一个单独的方法(显然是为了避免死锁)?

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

您的代码两次更新控件:

  • 使用对 的调用Invoke,它将另一个调用委托给OnHistoryUpdate。这是安全的,因为Invoke将执行编组到 UI 线程。
  • 调用后InvokeInvoke同步执行,当它返回时,您的代码将再次调用LoadTimeSeries,这次是不安全的(它不会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

如果您在需要从您的线程调用而不使用调用的控件上调用 Refresh,则预计会出现异常。确保你不这样做,你会没事的。这就是所有需要的。

于 2013-02-21T04:28:00.697 回答