In order to summarize the options, I will try to list them here (maybe it would be a good idea to make this a community wiki).
First of all, you can simply start a function in another thread:
Thread t = new Thread( ThreadProc );
t.Start();
// now you can wait for thread to finish with t.Join() or just continue
// Thread.IsBackground allows to control how thread lifetime influences
// the lifetime of the application
...
static void ThreadProc() {...} // can also be non-static, but for simplicity....
Then you can use BackgroundWorker
:
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += MyFunction;
bgWorker.RunWorkerAsync();
voud MyFunction(object o, DoWorkEventArgs args) {...}
You can use ProgressChanged
and RunWorkerCompleted
events for more control (as well as WorkerReportsProgress
and other properties)
Another option is to use ThreadPool
, if your method will not take too much time:
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
...
static void ThreadProc(Object stateInfo) { ... }
Yet another option is to call BeginInvoke
on a delegate:
public delegate int MyDelegate(...);
MyDelegate del = SomeFunction;
IAsyncResult ar = del.BeginInvoke(...);
int result = del.EndInvoke(ar);
This will execute on a thread from the thread pool. If you need to wait on calling thread, you can use IAsyncResult.IsCompleted
, but it will block the calling thread.
And of course, you can use Task
:
var task = Task.Factory.StartNew(() => MyMethod());
This will also execute MyMethod
on a thread from the thread pool, so the same warnings apply (although you can use TaskCreationOptions.LongRunning
to ensure that the new thread is always created). Under some circumstances (when you wait on task) it can even execute on the same thread, but it is well optimized so you should not worry about that.
This is probably the option with best tradeoff of simplicity vs control (of course, there is no really 'the best'). Here are the benefits (shamelessly stolen from Jon Skeet's answer):
- Adding continuations (Task.ContinueWith)
- Waiting for multiple tasks to complete (either all or any)
- Capturing errors in the task and interrogating them later
- Capturing cancellation (and allowing you to specify cancellation to start with)
- Potentially having a return value
- Using await in C# 5
- Better control over scheduling (if it's going to be long-running, say so when you create the task so the task scheduler can take that into account)