2010-02-18 80 views
4

我正在查看别人的代码,并没有太多的关于多线程的经验。我碰到这行代码:为什么在这里使用BeginInvoke?

BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });

我不知道为什么这样做时,只是这会工作:btnCalibrate.PerformClick();

谢谢您的回答。

回答

5

因为如果这个代码从创建GUI中的按钮,一个不同的线程中运行,一个异常将被抛出。后台线程不能直接调用GUI上的方法,因为GUI不是线程安全的。

当然,这仅仅是使用BeginInvoke合理的理由!但是找到包含咒语或魔法的代码并不是没有什么异常,因为作者看到另一个例子是这样做的,所以假设它在所有情况下都是必须的。如果你正在使用的代码是单线程的,那么这是不必要的。

特别是Windows窗体本身就是坚决单线程的。所有窗口和控件上的所有操作都发生在同一个线程上,并且它们的所有事件都在同一个线程上触发。一个GUI线程的使用是通过一个消息循环分区的,该循环持续在该线程上运行,并从队列中读取消息。 BeginInvoke的目的是最终将消息发布到该队列中,有效地说“当你有片刻时,请运行这段代码。”

+0

原谅我的无知,但btnCalibrate存在于“Form1的”和上面的代码上也存在“Form1的”。上面的代码存在于Form1.cs上的名为'void wm_OnWiimoteChanged'的函数中,'btnCalibrate_performClick'存在于同一个文件中。那么“不同线索”从哪里来? – Aishwar 2010-02-18 07:16:07

+0

如果你还可以建议一些文章,教育我这个话题,那将非常感谢! :) – Aishwar 2010-02-18 07:18:39

+1

@ aip.cd.aish:我喜欢这篇文章:http://msdn.microsoft.com/en-us/magazine/cc188732.aspx 啊...回忆... – codekaizen 2010-02-18 07:20:40

1

要在@Earwicker扩展位 - Control.BeginInvoke是从一个线程将电话转接到该公司拥有的控制实例的线程的方式。在背景中,这是通过被称为PostMessage到呼叫编组到拥有线程上的方法PerformClick一个Win32函数使用Win32消息。这是由于Win32 Windows以及扩展WinForms Controls所必需的,只能从创建它的线程(通常是运行GUI的单线程)进行访问。

原因BeginInvoke用于对Invoke是因为前者使用PostMessage,并立即返回,而后者使用的幕后 SendMessage,并需要等待 PostMessage,并等待来自GUI线程的答复。这可以延迟进行呼叫的线程,甚至锁定应用程序,因此BeginInvoke是更好的选择。

+0

调用不使用SendMessage。它也使用PostMessage,但在返回之前等待结果。 – Andy 2010-07-05 19:30:33

+0

@安迪 - 很好。虽然在实践中,您以类似于PostMessage/SendMessage的方式使用BeginInvoke/Invoke,但SendMessage(跳转消息队列和向右移动到WinProc)与PostMessage/Wait的行为不同,足以使此区分工作保持不变。我从来没有注意到,因为我的用法没有实际的区别。 – codekaizen 2010-07-05 19:45:12