What is the best way to work with threads in C #?

What is the best way to work with threads (methods) in C #?

For instance:

Let's say I have a form and you want to load data from db.

My form controls: - dataGridView (to show data from DB), - label (loading status) and - button (start loading). 

When I click the button, my form freezes until the task is completed. Also, the download status does not change until the task is completed. I think asynchronous threading will be the answer?

So my question is: what's the best way to handle this? I know there are a lot of things about Threading, but what is the difference between them and how do you make it thread safe?

How do you solve such problems?

Regards.

+4
source share
4 answers

There is no universal “best” way to work with threads. I'm afraid you just need to try different ways to do something.

I especially like the continuation idea of ​​Jeremy D. Miller described on this page (scroll down to find the "continuation" section). It is really elegant and means very little coding.

Basically, when you call "ExecuteWithContinuation" with the Func argument, the function executes asynchronously, and then returns the action when it ends. The action is then transferred back to your UI thread to act as a continuation. This allows you to quickly split your operations into two bits:

  • Perform a lengthy operation that should not block the user interface
  • ... when done, update the user interface in the user interface thread.

It takes some getting used to, but it's pretty cool.

 public class AsyncCommandExecutor : ICommandExecutor { private readonly SynchronizationContext m_context; public AsyncCommandExecutor(SynchronizationContext context) { if (context == null) throw new ArgumentNullException("context"); m_context = context; } public void Execute(Action command) { ThreadPool.QueueUserWorkItem(o => command()); } public void ExecuteWithContinuation(Func<Action> command) { ThreadPool.QueueUserWorkItem(o => { var continuation = command(); m_context.Send(x => continuation(), null); }); } } 

Then you should use it like this (forgive formatting ...)

 public void DoSomethingThatTakesAgesAndNeedsToUpdateUiWhenFinished() { DisableUi(); m_commandExecutor.ExecuteWithContinuation( () => { // this is the long-running bit ConnectToServer(); // This is the continuation that will be run // on the UI thread return () => { EnableUi(); }; }); } 
+2
source

If you are using Windows Forms, you should look at BackrgroundWorker . More generally, it is often useful to use the ThreadPool class. And finally, take a look at the new .NET 4 Parallel class.

+7
source

You can use this template: -

  private void RefreshButton_Click(object sender, EventArgs e) { MessageLabel.Text = "Working..."; RefreshButton.Enabled = false; ThreadPool.QueueUserWorkItem(delegate(object state) { // do work here // eg object datasource = GetData(); this.Invoke((Action<object>)delegate(object obj) { // gridview should also be accessed in UI thread // eg MyGridView.DataSource = obj; MessageLabel.Text = "Done."; RefreshButton.Enabled = true; }, datasource); }); } 
+1
source

You cannot access your controls from the code that runs in the selection thread - the framework does not allow this, which explains the error you received.

You need to cache the data extracted from db in an object other than the form, and fill your user interface with data from this object after the background workflow has completed (and process the synchronization to access this object).

0
source

All Articles