问题描述
每当初学者问类似:如何更新GUI ?从C#中的另一个线程,答案是pretty的直:
Anytime the beginner asks something like: How to update GUI from another thread in C#?, the answer is pretty straight:
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
这是真的很好用吗?非GUI线程执行后右 foo.InvokeRequired
富
的状态可以改变。举例来说,如果我们在 foo.InvokeRequired
收的形式对的,但在此之前 foo.BeginInvoke
,要求 foo.BeginInvoke
将导致 InvalidOperationException异常
:调用或BeginInvoke不能调用控件上,直到窗口句柄已创建。 的这不会发生,如果我们在调用之前关闭的形式 InvokeRequired
,因为这将是假
连从非GUI线程调用的时候。
But is it really good to use it? Right after non-GUI thread executes foo.InvokeRequired
the state of foo
can change. For example, if we close form right after foo.InvokeRequired
, but before foo.BeginInvoke
, calling foo.BeginInvoke
will lead to InvalidOperationException
: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired
, because it would be false
even when called from non-GUI thread.
另一个例子:比方说,富
是文本框
。如果关闭的形式,而且非GUI线程执行后 foo.InvokeRequired
(这是假的,因为窗体被关闭)和 foo.AppendText
这将导致的ObjectDisposedException
。击>
在此相反,在使用 WindowsFormsSynchronizationContext
我的意见是非常容易 - 使用帖子发布回调
将出现只有当螺纹依然存在,并同步调用使用发送
抛出 InvalidAsynchronousStateException
如果线程不存在了。
In contrast, in my opinion using WindowsFormsSynchronizationContext
is much easier - posting callback by using Post
will occur only if thread still exists, and synchronous calls using Send
throws InvalidAsynchronousStateException
if thread not exists anymore.
时没有使用 WindowsFormsSynchronizationContext
只是更容易?我失去了一些东西?为什么要使用InvokeRequired-的BeginInvoke模式,如果它没有真正线程安全的?你认为什么是更好的?
Isn't using WindowsFormsSynchronizationContext
just easier? Am I missing something? Why should I use InvokeRequired-BeginInvoke pattern if it's not really thread safe? What do you think is better?
推荐答案
使用反射器,我们可以看到, WindowsFormsSynchronizationContext
:
Using Reflector we could see that WindowsFormsSynchronizationContext
:
- 使用
的BeginInvoke
为发布
无任何检查。无用本身只需要直接调用该函数。 - 使用
调用
只测试该线程是活在发送
(丹尼尔·Hilgarth说的)。如果你有引用由另一个线程拥有的控制和活得比它,你已经有了一个问题,所以它不会改变任何东西,除了少数情况下,UI线程会活得比上创建控件辅助线程... 李>
- Uses
BeginInvoke
forPost
without any checks. Useless in itself just call the function directly. - Uses
Invoke
testing only that the thread is alive onSend
(As Daniel Hilgarth said). If you have a secondary thread that reference a control owned by another thread and outlive it you already got a problem so it doesn't change anything and except in a few cases the UI thread will outlive controls created on it...
击>
确定正确的阅读它真的取决于你想要做的委托作为 WindowsFormsSynchronizationContext
基本上自身附加到只是为了这个目的而创建一个特殊的控制什么。因此,无论的BeginInvoke和调用会一直工作作为你的线程是活着的消息泵(由Application.Run启动)正在执行。
Ok reading correctly it really depends on what you want to do in the delegate as WindowsFormsSynchronizationContext
basically attach itself to a special control created just for this purpose. So both BeginInvoke and Invoke will work as long as your thread is alive and the message pump (started by Application.Run) is executing.
所以,如果你使用 WindowsFormsSynchronizationContext
你可能在你调用对象的委托,它不具有任何处理,被放置很久以前的情况是(这样的的通话将失败与 InvalidOperationException异常
其他)......它会出现,只要你访问什么,取决于手柄和崩溃后,当你改变了$ C $工作C(或当你的团队不太实验开发商不差):你应该早失败
So if you uses WindowsFormsSynchronizationContext
you risk being in a case where you call a delegate on an object that doesn't have any handle and was disposed long time ago (Such call will have failed with InvalidOperationException
otherwise)... It will appear to work as long as you access nothing that depends on the handle and crash later when you change the code (or worse when a less experimented developer on you team does) : You should fail early.
我的结论将是 WindowsFormsSynchronizationContext
应保留至您需要与另一个线程的消息泵进行交互,可能是由于一些方法线程亲和具体案件。对于简单的如何从一个计时器更新自己的状态情况下,它会误导新人,并带领他们到微妙的错误,不是一个好主意, InvokeRequired
真的是更适合于90 %用法。
My conclusion would be that WindowsFormsSynchronizationContext
should be reserved to specific cases where you need to interact with a message pump on another thread, maybe due to some method thread-affinity. For simple "how do I update my form from a timer" cases it will mislead newcomers and lead them to subtle bugs, not a good idea, InvokeRequired
is really more suited to 90% of usages.
这篇关于为什么InvokeRequired pferred超过WindowsFormsSynchronizationContext $ P $?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!