当两个线程同时访问时,跨线程InvalidOperationException,InvokeRequired==fals
本文关键字:线程 InvalidOperationException fals InvokeRequired 访问 两个 | 更新日期: 2023-09-27 18:00:18
一个控件由两个工作线程访问,第二个工作线程在第一个工作线程完成它在控件上的工作之前访问。第二个线程(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
您的代码更新控件两次:
- 使用对
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);
}
如果在不使用invoke的情况下对需要从线程调用的控件调用Refresh,则会得到异常。确保你不这样做,你会没事的。这就是我们所需要的。