我已经看到了对 GUI 控件的跨线程访问的常见设置,例如这里讨论的: Shorest way to write a thread-safe access method to a windows forms control
我发现的所有网络点击都描述了类似的事情。
但是,为什么我们需要检查 InvokeRequired?我们不能直接调用 Invoke 吗?
我认为答案是否定的,所以我真正的问题是“为什么”?
我已经看到了对 GUI 控件的跨线程访问的常见设置,例如这里讨论的: Shorest way to write a thread-safe access method to a windows forms control
我发现的所有网络点击都描述了类似的事情。
但是,为什么我们需要检查 InvokeRequired?我们不能直接调用 Invoke 吗?
我认为答案是否定的,所以我真正的问题是“为什么”?
从非 UI 线程我们无法触及 UI - 可能会发生非常糟糕的事情,因为控件具有线程关联性。因此,我们必须(至少)从非 UI 线程调用Invoke
或BeginInvoke
.
然而,对于 UI 线程——我们不想调用Invoke
很多时间;问题是,如果您已经在 UI 线程上,它仍然具有向表单的泵发送消息并进行处理的不必要开销。
实际上,在大多数线程代码中,您都知道您希望在非UI 线程上调用特定方法,因此在这些情况下,没有额外的开销:只需调用Invoke
.
InvokeRequired
基本上会告诉您是否在正确的线程上执行。如果您不在正确的线程上,则需要将任务编组到正确的线程,否则您不需要。因此需要进行检查。
如果您尝试在创建窗口句柄之前调用(例如,在调用表单构造函数时),您将获得一个InvalidOperationException
. 因此,通常InvokeRequired
需要检查。
有关详细信息,请参阅MSDN。
问题是 GUI 控件要求只有在用于实例化 GUI 控件的同一线程上执行的代码才能访问 GUI 控件。此要求背后的原因与 Windows 的架构方式有关。可以说,要改变这一点非常困难。
InvokeRequired 根据实例化线程的身份检查当前执行线程的身份。如果它们相同,则代码可以自由地与控件交互。如果不是,代码必须将数据从当前线程编组到实例化线程。这是一个缓慢且成本高昂的过程,应尽可能避免。如果您总是调用,您的代码将起作用,并且您可能不会注意到性能下降,但是随着多核系统的使用,这种情况将越来越普遍。最好不要创建以后必须撤消的代码“结”。
Invoke 将通过 Delegate 而不是直接调用代码,这将是昂贵的。
仅在需要时调用 Invoke 具有成本效益。因此,InvokeRequired 用于找出调用是来自同一个线程还是另一个线程?
我能想到的一个原因是性能。如果大多数时候调用线程与创建线程相同,那么您将有一些不必要的开销。