【发布时间】:2014-09-24 15:11:57
【问题描述】:
我有一个 Worker 类和一个 MainForm/UI 类。从 UI 类中,我在新的后台线程中创建了 Worker 类的新实例。该线程将一些更新编组回 UI 的控件。由于它们在不同的类中,我基本上将 MainForm 实例 (this) 和适当的委托传递给工作类的构造函数以更新控件。在构造函数中,我将 mainForm 设置为 ISynchronizeInvoke 对象(称为 _synch),然后,在工作类的更下方,我执行 _synch.Invoke(theDelegate, new object[] { "new value" })。
一切都很好,但后来我意识到也可以只使用mainForm.Invoke(不使用ISynchronizeInvoke 对象)。两者有什么区别?
更糟糕的是,我在一篇文章中读到 ISynchronizeInvoke 已经不再需要太多了,现在 SynchronizationContext 已经出现了很长时间。我意识到我不明白这两个是为了什么。对于理解为什么我应该在这些对象上使用 Invoke 而不是直接在 mainForm 上使用的任何帮助,我们将不胜感激。
【问题讨论】:
-
ISynchronizeInvoke 仅对不不知道哪个特定线程是 UI 线程或如何正确调用操作 UI 的代码的另一个库有用。 Form 类从来都不是问题,它是 UI。并实现使 ISynchronizeInvoke 工作的管道。遗憾的是,WPF 违反了合同,因此它不再是通用接口。
-
@HansPassant 谢谢汉斯。我尝试按照 Sriram 的建议切换到
SynchronizationContext,但 Send 和 Post 不接受自定义代表。他们采用只有一个参数 (object) 的 SendOrPostCallback 委托。我当前的自定义委托有一个值字符串(我希望标签采用的文本)和一个字符串 lbName,以便该方法可以识别要更新的标签控件。你建议我在这里做什么?我应该坚持使用 Form.Invoke 吗?谢谢! -
99% 的情况下使用 Invoke 都是错误的。非常容易出现死锁和竞争,请始终使用 BeginInvoke。单个对象足以存储任何东西,必要时使用小的帮助类。 lambda 几乎总是方便的选择。
-
@HansPassant BeginInvoke 在我的情况下不起作用,因为我在彼此下方有几个调用(在
while(!mre.WaitOne(50))循环中更新不同的标签。所以如果我使用 BeginInvoke,标签会结结巴巴,而不是更新顺利。我无法给出一个很好的技术解释为什么。关于 SynchronizationContext 的话题,在这里做这个似乎是一个糟糕的决定,因为我必须创建一个前面提到的帮助器类(附加代码/复杂性),当我没有真正得到任何回报时。Form.Invoke 在这种情况下与 _synch.Send 具有相同的效果。你不同意吗?
标签: c# multithreading synchronization