Is the thread that you want to monitor your code? If so, you could wrap the whole thing in a class, and either raise an event when you finish or use a WaitHandle (I would use a ManualResetEvent) to signal completion. -- completely encapsulate the background logic. You can also use this encapsulation to capture an exception and then raise an event.
Something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace BackgroundWorker
{
public class BackgroundWorker
{
///
/// Raised when the task completes (you could enhance this event to return state in the event args)
///
public event EventHandler TaskCompleted;
///
/// Raised if an unhandled exception is thrown by the background worker
///
public event EventHandler BackgroundError;
private ThreadStart BackgroundTask;
private readonly ManualResetEvent WaitEvent = new ManualResetEvent(false);
///
/// ThreadStart is the delegate that you want to run on your background thread.
///
///
public BackgroundWorker(ThreadStart backgroundTask)
{
this.BackgroundTask = backgroundTask;
}
private Thread BackgroundThread;
///
/// Starts the background task
///
public void Start()
{
this.BackgroundThread = new Thread(this.ThreadTask);
this.BackgroundThread.Start();
}
private void ThreadTask()
{
// the task that actually runs on the thread
try
{
this.BackgroundTask();
// completed only fires on successful completion
this.OnTaskCompleted();
}
catch (Exception e)
{
this.OnError(e);
}
finally
{
// signal thread exit (unblock the wait method)
this.WaitEvent.Set();
}
}
private void OnTaskCompleted()
{
if (this.TaskCompleted != null)
this.TaskCompleted(this, EventArgs.Empty);
}
private void OnError(Exception e)
{
if (this.BackgroundError != null)
this.BackgroundError(this, new BackgroundWorkerErrorEventArgs(e));
}
///
/// Blocks until the task either completes or errrors out
/// returns false if the wait timed out.
///
/// Timeout in milliseconds, -1 for infinite
///
public bool Wait(int timeout)
{
return this.WaitEvent.WaitOne(timeout);
}
}
public class BackgroundWorkerErrorEventArgs : System.EventArgs
{
public BackgroundWorkerErrorEventArgs(Exception error) { this.Error = error; }
public Exception Error;
}
}
Note: you need some code to keep Start from being called twice, and you might want to add a state property for passing state to your thread.
Here's a console app that demonstrates the use of this class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BackgroundWorker
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Test 1");
BackgroundWorker worker = new BackgroundWorker(BackgroundWork);
worker.TaskCompleted += new EventHandler(worker_TaskCompleted);
worker.BackgroundError += new EventHandler(worker_BackgroundError);
worker.Start();
worker.Wait(-1);
Console.WriteLine("Test 2");
Console.WriteLine();
// error case
worker = new BackgroundWorker(BackgroundWorkWithError);
worker.TaskCompleted += new EventHandler(worker_TaskCompleted);
worker.BackgroundError += new EventHandler(worker_BackgroundError);
worker.Start();
worker.Wait(-1);
Console.ReadLine();
}
static void worker_BackgroundError(object sender, BackgroundWorkerErrorEventArgs e)
{
Console.WriteLine("Exception: " + e.Error.Message);
}
private static void BackgroundWorkWithError()
{
throw new Exception("Foo");
}
static void worker_TaskCompleted(object sender, EventArgs e)
{
Console.WriteLine("Completed");
}
private static void BackgroundWork()
{
Console.WriteLine("Hello!");
}
}
}