control.BeginInvoke() Vs Dispatcher Vs SynchronizationContext Vs .. - RELIABILITY
Invoking a UI thread from a worker thread is discussed lot of times and we know why to use BeginInvoke() instead of Invoke(). I recently posted this question and after doing some research I found out that there are at least three different ways (internally they might be same) to invoke (asynchronously) something on UI thread.
Control.BeginInvoke()
- Using
SynchronizatoinContext
Class 开发者_运维知识库
- Using
Dispatcher.BeginInvoke(priority.. )
Can anyone tell me which is a RELIABLE way to asynchronously call a method to be executed on UI thread. Any experience ? I see Dispatcher.BeginInvoke has priority component to it, does it make it more reliable ?
Context:
we are usingsomeControl.BeginInvoke()
but noticed that sometimes (unfortunately only in the end user production environment) the delegate passed to BeginInvoke is
never executed which makes me believe that the post message which it creates is getting lost. We want a reliable way to communicate back to the UI thread. control.Invoke()
sometimes hang the UI so we don't want to go there either. They all operate as they should, if you call BeginInvoke
and sometimes nothing happens, there's some problem in the environment or calling code, probably - it's not that BeginInvoke
is unreliable. Well - there could be a bug, but it's far less likely.
Perhaps you could give more context and we can help diagnose.
SynchronizationContext is more abstract and adaptable in more case. It is a wrapper of specific implementation. MSDN says "Providers of synchronization models can extend this class and provide their own implementations for these methods".
You should be careful with lambda functions and BeginInvoke. I had code like this that resulted in all sorts of weird behavior.
MyThing thing;
while( GetThing(ref thing)) {
control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}
The problem is that thing
is not evaluated when you create the lambda function. It is evaluated when the lamdba function gets executed. But it is bound to a variable that is changing at the same time in the producer thread.
You can fix this problem by declaring a local variable copy of thing
MyThing thing;
while( GetThing(ref thing)) {
MyThing thing_x = thing;
control.BeginInvoke((Action)(() => control.Text = thing_x.ToString()));
}
Or you can put the BeginInvoke ugliness in a wrapper
MyThing thing;
while( GetThing(ref thing)) {
SetText(thing);
}
void SetText(MyThing thing)
control.BeginInvoke((Action)(() => control.Text = thing.ToString()));
}
精彩评论