control.BeginInvoke()VS Dispatcher与SynchronizationContext Vs .. - 可靠性

时间:2011-06-13 15:04:22

标签: c# delegates

很多次讨论从工作线程调用UI线程,我们知道为什么要使用BeginInvoke()而不是Invoke()。我最近发布了this question,在做了一些研究之后,我发现在UI线程上调用(异步)某些东西至少有三种不同的方式(内部可能相同)。

  1. Control.BeginInvoke()
  2. 使用SynchronizatoinContext Class
  3. 使用Dispatcher.BeginInvoke(priority.. )
  4. 任何人都可以告诉我哪种方法可以异步调用在UI线程上执行的方法。有经验吗?我看到Dispatcher.BeginInvoke具有优先级组件,它是否使它更可靠?

    上下文
    我们正在使用someControl.BeginInvoke()但注意到有时(不幸的是只在最终用户生产环境中)传递给BeginInvoke is的委托从未执行过,这使我相信它创建的帖子消息会丢失。我们想要一种可靠的方式来回传到UI线程。 control.Invoke()有时挂起用户界面,所以我们也不想去那里。

3 个答案:

答案 0 :(得分:0)

他们都按照自己的意愿运作,如果你打电话给BeginInvoke,有时没有任何事情发生,那么环境或调用代码就会出现问题 - 可能不是BeginInvoke不可靠。嗯 - 可能有一个错误,但它的可能性要小得多。

也许您可以提供更多背景信息,我们可以帮助诊断。

答案 1 :(得分:0)

在更多情况下,SynchronizationContext更具抽象性和适应性。它是具体实现的包装器。 MSDN说“同步模型的提供者可以扩展这个类并为这些方法提供他们自己的实现”。

答案 2 :(得分:0)

你应该小心lambda函数和BeginInvoke。我有这样的代码导致各种奇怪的行为。

MyThing thing;
while( GetThing(ref thing)) {
    control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}

问题是在创建lambda函数时不会评估thing。在lamdba函数执行时进行评估。但它绑定到一个在生产者线程中同时发生变化的变量。

您可以通过声明thing

的本地变量副本来解决此问题
MyThing thing;
while( GetThing(ref thing)) {
  MyThing thing_x = thing;
  control.BeginInvoke((Action)(() => control.Text = thing_x.ToString()));
}

或者你可以将BeginInvoke丑陋放在包装器中

MyThing thing;
while( GetThing(ref thing)) {
  SetText(thing);
}

void SetText(MyThing thing)
  control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}