交叉线程InvalidOperationException,当同时由2个线程访问时,InvokeRequired == false

时间:2013-02-21 04:16:15

标签: c# .net multithreading invoke invokerequired

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

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

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

2 个答案:

答案 0 :(得分:1)

您的代码更新了控件两次:

  • 使用Invoke的来电,该来电将另一个电话委托给OnHistoryUpdate。这是安全的,因为Invoke将执行封送到UI线程。
  • 致电Invoke后。 Invoke同步执行,当它返回您的代码时,将第二次调用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);    
}

答案 1 :(得分:0)

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