6

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.

  1. Control.BeginInvoke()
  2. Using SynchronizatoinContext Class
  3. 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 using someControl.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.

Community
  • 1
  • 1
karephul
  • 1,473
  • 4
  • 19
  • 36

3 Answers3

0

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".

Steel
  • 125
  • 2
  • 7
  • SynchronizationContext is perferred here: http://social.msdn.microsoft.com/Forums/en-US/async/thread/1218c86e-fa9b-45a6-93b0-5e27616a6c21 – Steel Dec 13 '12 at 05:22
0

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()));
}
Mark Lakata
  • 19,989
  • 5
  • 106
  • 123
0

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.

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • Thanks for the response. I have a similar scenario in our code. http://stackoverflow.com/questions/6270514/control-begininvoke-fails-to-call-the-delegate – karephul Jun 13 '11 at 15:18
  • Hi karephul, that's interesting but doesn't help out much in this case since they didn't find an answer either. What is your basic setup in terms of threads, processes, locks, etc? – Kieren Johnstone Jun 13 '11 at 15:27
  • Oh... is that the same problem? Just reposted here ? – Kieren Johnstone Jun 13 '11 at 15:28
  • There is a flaw in your logic in the other example. If there is an exception on the UI thread, `executing` stays as `true` and the method will not be called anymore. Perhaps that is what is happening. – Kieren Johnstone Jun 13 '11 at 15:30