6

Trying to wrap my head around updating UI controls from other threads.

Currently using BeginInvoke and honestly it's working fine but I keep hearing about how you can use SynchronizationContext as well to do the same thing.

Which is preferred?

Also, is it bad practice to update the UI from a thread? Would it be better to raise an event and have the main form handle it instead or are there other preferable ways to do that as well?

Sorry for the somewhat subjective question but there are so many options in the world of threading and I'm trying to grasp their differences and where each of them are applicable, along with best practices for writing readable and extendable code for the future.

Edit: Also now I see there is the TaskScheduler.FromCurrentSynchronizationContext route as well.. So many choices x_x

John Smith
  • 8,567
  • 13
  • 51
  • 74
  • You should generally favor higher level abstractions in threading to help yourself fall into the pit of success. Getting threading right is difficult. Favor Task or BackgroundWorker. – Hans Passant Sep 20 '11 at 05:34

2 Answers2

7

I prefer SynchronizationContext over Control.Invoke. The danger of Control.Invoke is that there is a lifetime issue with the owning Control. If the Control is disposed while you are trying to Invoke on it then it compromises the ability of the call to succeed. This happens when dialogs are closed, views shifted, etc ...

SynchronizationContext.Current though generally lives as long as the thread it's associated with. It does have a finite lifetime and hence ultimately the same problems but it's a bit more predictable than a Control.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 3
    I don't think this sentence is correct "If the Control is disposed while you are trying to Invoke on it then it compromises the ability of the call to succeed..." because actually the WindowsFormsSynchronizationContext that is the concrete impl of SynchronizationContext, use exactly Control.Invoke to do the marshalling `Control control = this.controlToSendTo; object[] objArray = new object[] { state }; control.Invoke(d, objArray);`, I would say I prefer SynchronizationContext just because is an abstraction, and if Microsoft change the concrete implementation, you don't have to change your code – Michael Denny Jun 16 '14 at 18:25
  • @MichaelDenny, The `controlToSendTo` is maintained by the `SyncContext` and has the same lifetime as the thread hence won't be disposed, whereas the control of `Control.Invoke` might have already been disposed for example when form closed – Eben Apr 29 '18 at 05:28
0

Have you looked into using a Background Worker component? For long running tasks that shouldn't tie up the UI it is a clean and easy way to get multithreading capabilites. For instance you can perform updates to the UI using the ProgressChanged Event and the background worker and the background worker class will ensure that the thread that created the BW is the one that executes the ProcessChanged and WorkComplete event. So if you made the BW from the UI and set it off to work then you can update the UI safely from there.

Here's a quick article from MS http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx

Another really good link http://www.albahari.com/threading/part3.aspx#_BackgroundWorker

Jason Turan
  • 1,302
  • 12
  • 20
  • I am familiar with the BackgroundWorker but this project is for a server application so Tasks/ThreadPool is more suitable for this I believe. Otherwise you are correct though. Probably should have included that in the original post. My apologies. – John Smith Sep 20 '11 at 05:53
  • @John Why do you have UI controls on a server application? – adrianm Sep 20 '11 at 11:06
  • After reading the question a second time I'm thinking John is asking two questions here. 1 is using Synchronization and two is best way to handle multithreading in UI – Jason Turan Sep 21 '11 at 01:26