Returning a value from thread?
One of the easiest ways to get a return value from a thread is to use closures. Create a variable that will hold the return value from the thread and then capture it in a lambda expression. Assign the "return" value to this variable from the worker thread and then once that thread ends you can use it from the parent thread.
void Main(){ object value = null; // Used to store the return value var thread = new Thread( () => { value = "Hello World"; // Publish the return value }); thread.Start(); thread.Join(); Console.WriteLine(value); // Use the return value here}
It depends on how do you want to create the thread and available .NET version:
.NET 2.0+:
A) You can create the Thread
object directly. In this case you could use "closure" - declare variable and capture it using lambda-expression:
object result = null;Thread thread = new System.Threading.Thread(() => { //Some work... result = 42; });thread.Start();thread.Join();Console.WriteLine(result);
B) You can use delegates and IAsyncResult
and return value from EndInvoke()
method:
delegate object MyFunc();...MyFunc x = new MyFunc(() => { //Some work... return 42; });IAsyncResult asyncResult = x.BeginInvoke(null, null);object result = x.EndInvoke(asyncResult);
C) You can use BackgroundWorker
class. In this case you could use captured variable (like with Thread
object) or handle RunWorkerCompleted
event:
BackgroundWorker worker = new BackgroundWorker();worker.DoWork += (s, e) => { //Some work... e.Result = 42;};worker.RunWorkerCompleted += (s, e) => { //e.Result "returned" from thread Console.WriteLine(e.Result);};worker.RunWorkerAsync();
.NET 4.0+:
Starting with .NET 4.0 you could use Task Parallel Library and Task
class to start your threads. Generic class Task<TResult>
allows you to get return value from Result
property:
//Main thread will be blocked until task thread finishes//(because of obtaining the value of the Result property)int result = Task.Factory.StartNew(() => { //Some work... return 42;}).Result;
.NET 4.5+:
Starting with .NET 4.5 you could also use async
/await
keywords to return value from task directly instead of obtaining Result
property:
int result = await Task.Run(() => { //Some work... return 42; });
Note: method, which contains the code above shoud be marked with async
keyword.
For many reasons using of Task Parallel Library is preferable way of working with threads.
I would use the BackgroundWorker approach and return the result in e.Result.
EDIT:
This is commonly associated with WinForms and WPF, but can be used by any type of .NET application. Here's sample code for a console app that uses BackgroundWorker:
using System;using System.Threading;using System.ComponentModel;using System.Collections.Generic;using System.Text;namespace BGWorker{ class Program { static bool done = false; static void Main(string[] args) { BackgroundWorker bg = new BackgroundWorker(); bg.DoWork += new DoWorkEventHandler(bg_DoWork); bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted); bg.RunWorkerAsync(); while (!done) { Console.WriteLine("Waiting in Main, tid " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(100); } } static void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { Console.WriteLine("Completed, tid " + Thread.CurrentThread.ManagedThreadId); done = true; } static void bg_DoWork(object sender, DoWorkEventArgs e) { for (int i = 1; i <= 5; i++) { Console.WriteLine("Work Line: " + i + ", tid " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(500); } } }}
Output:
Waiting in Main, tid 10Work Line: 1, tid 6Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Work Line: 2, tid 6Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Work Line: 3, tid 6Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Work Line: 4, tid 6Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Work Line: 5, tid 6Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Waiting in Main, tid 10Completed, tid 6
2014 UPDATE
See @Roger's answer below.
https://stackoverflow.com/a/24916747/141172
He points out that you can use a Task that returns a Task<T>
, and check Task<T>.Result
.