4

I understand that the .Join() causes the threads to pause and wait till a thread finishes its work but how can I avoid the UI from getting frozen? This is what my codes look like"

Thread dataThread = new Thread(()=> data = getData(id));
dataThread.Start();
dataThread.Join();

Thread storingThread = new Thread(()=> storeData(data));
storingThread.Start();

I need to have the Join since the first thread returns an object containing data that needs to be stored through the second thread. But this causes a UI freeze. How can I implement these in maybe a Background thread? What do yall think I should change?

Jay
  • 4,873
  • 7
  • 72
  • 137

5 Answers5

4

If you are using .Net framework >= 4.5 you can use Tasks

await Task.Run(() => data = getData(id));
await Task.Run(() => storeData(data));

Or in one command

await Task.Run(() => storeData(getData(id)));

If you don't have to wait till it's finished you can also do:

Task.Run(() => storeData(getData(id)));
Simon
  • 1,244
  • 8
  • 21
  • This gives an error: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. – Jay May 16 '15 at 13:58
  • 1
    @Earthling add to your function the `async` modifire. e.g. your normal funciton is `private void DoStuff()` then change it to `private async void DoStuff()` – Simon May 16 '15 at 13:59
  • 1
    @Simon if he is using .Net 4 its `Task.Factory.StartNew` without the await. – ΩmegaMan May 16 '15 at 14:03
2

It seems you don't need two threads:

Thread dataThread = new Thread(() => storeData(getData(id)));
dataThread.Start();

Note, that Task is preferable to Thread. Also, you probably should make use of await.

usr
  • 168,620
  • 35
  • 240
  • 369
  • 1
    This should have been the accepted answer I would have thought. Particularly when it compiles under .NET 4. Plus it is arguably more elegant with a single thread –  May 16 '15 at 14:16
  • @MickyDuncan this works too but I used Task instead of the Threads and it seemed to do the trick! :) – Jay May 16 '15 at 14:19
  • While starting a new thread works. It might give more overhead than needed. A task doesn't necessarily start on a new thread (saving the overhead). See http://stackoverflow.com/a/13429164/1277156 (for extra explaining) – Measurity May 16 '15 at 14:24
  • Sure, I don't think this is a good solution. This is the minimal delta needed to get his code to work. He made things more complicated than needed. – usr May 16 '15 at 20:56
  • It met the OP's requirements of `.NET4` without requiring a drastic re-write. –  May 17 '15 at 05:40
2

Put the whole work into one thread so the UI doesn't stop:

 ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));

Or for .Net 4

Task.Factory.StartNew(() => storeData(getData(id)));
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • 2
    Before you use this you can just do `ThreadPool.QueueUserWorkItem( () => storeData(getData(id)));` – Simon May 16 '15 at 13:58
  • @Simon...I agree, let me change the answer. – ΩmegaMan May 16 '15 at 14:01
  • @MickyDuncan I do not disagree with what you said, my goal was simply to move the operations off of the *GUI* thread for the user, to change the appearance of a hung system. I surmised he could optimize the process later. – ΩmegaMan May 16 '15 at 14:28
  • 1
    You're **already** _"off the GUI thread"_ by using `ThreadPool.QueueUserWorkItem`. –  May 17 '15 at 05:38
  • @MickyDuncan I have updated the first part of my answer to match the second part; to avoid any confusion. – ΩmegaMan May 17 '15 at 14:22
  • @MickyDuncan I truly understood what you were getting at... it wasn't clear to me if the user was doing other things in those threads but not shown(?), so I just copied *the process* over. But I appreciated the comments by all and adjusted. :-) – ΩmegaMan May 17 '15 at 14:33
  • That is fine. I respect that you wanted to keep the essence of his original code. :) –  May 17 '15 at 15:03
2

Use the async / await keywords. Small example code:

private async void Method()
{
     var result = await ExecuteAsync();
     // result == true 
}

private async Task<bool> ExecuteAsync()
{
     //run long running action
     return true;
}

In .net 4.0 you need to install Microsoft.Bcl.Async to use this feature.

A good introduction in this feature can be read on http://blog.stephencleary.com/2012/02/async-and-await.html

Florian Moser
  • 2,583
  • 1
  • 30
  • 40
  • Generally, the only time you should have a method marked as `async void` is for event handlers such as UI. Consider making it `async Task` instead. _[With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx)_ –  May 17 '15 at 05:51
  • I know. I'm pretty sure Earthling is calling those two Actions he mentioned above after User Input. My `Method()` would be the event handler. – Florian Moser May 17 '15 at 09:40
2

The answer has already been given. Just as an extra, I give mine.

You can also use ContinueWith like this:

Task<string>.Factory.StartNew(() => "Hey!").ContinueWith(t => Console.WriteLine(t.Result));
Measurity
  • 1,316
  • 1
  • 12
  • 24
  • This is a bit overkill. The user didn't even knew TPL yet – Simon May 16 '15 at 14:12
  • @Simon I'm just throwing it out. And it's normal C#. Overkill is debatable. Though I agree it's more advanced. – Measurity May 16 '15 at 14:13
  • How is this relevant to `getData()` and `storeData` context provided in the OP's question? –  May 16 '15 at 14:14
  • @MickyDuncan He can replace the Task with Task.Factory.StartNew() => getData(id)).ContinueWith(t => storeData(t.Result)) and works for .net 4 as well. – Measurity May 16 '15 at 14:16
  • True, but consider rewriting it so that the OP does not need to do any rewriting. Thanks –  May 16 '15 at 14:19
  • @MickyDuncan Stackoverflow isn't really here for giving plane answers (though I do that often). I expect the user to do some self research sometimes so they actually learn something. – Measurity May 16 '15 at 14:20