|
QueueUserWorkItem() vs. Start() |
2004-04-05 |
|
I caught a conversation yesterday along the lines of “work intiated by QueueUserWorkItem won’t complete if the main thread exits, but work initiated by Thread.Start will.” The .Net threading APIs are a pleasure to use, but there are a couple of little catches for the unwary. One of these is the difference between foreground and background threads. The behaviour described above is certainly the way it looks out of the box: pool threads (the threads used by QueueUserWorkItem) are background threads by default, whereas threads created by the programmer are foreground threads. The thing to note here is that threads can be switched from foreground to background mode. Consider the following example1, which creates a foreground thread via QueueUserWorkItem:
/*
1. Uses QueueUserWorkItem, waits for second thread to complete before unloading app domain
*/
class ThreadTest {
static void Main() {
System.Console.WriteLine("Main method 1");
System.Threading.WaitCallback callback = new
System.Threading.WaitCallback(Work);
System.Threading.ThreadPool.QueueUserWorkItem(callback);
System.Threading.Thread.Sleep(0);
System.Console.WriteLine("Main method 2");
}
static void Work(object state) {
System.Threading.Thread.CurrentThread.IsBackground = false;
System.Console.WriteLine("New thread work 1");
System.Threading.Thread.Sleep(10000);
System.Console.WriteLine("New thread work 2");
System.Threading.Thread.CurrentThread.IsBackground = true;
}
}
By manipulating the IsBackground property, I can also manually create a background thread, which will not stop the app domain from unloading:
/*
2. Uses Thread.Start, does not wait for second thread to complete before unloading app domain
*/
class ThreadstartTest {
static void Main() {
System.Threading.ThreadStart start = new System.Threading.ThreadStart(
ThreadstartTest.Work
);
System.Console.WriteLine("Main method 1");
System.Threading.Thread newThread = new System.Threading.Thread(start);
newThread.IsBackground = true;
newThread.Start();
System.Console.WriteLine("Main method 2");
}
private static void Work() {
System.Console.WriteLine("New thread work 1");
System.Threading.Thread.Sleep(10000);
System.Console.WriteLine("New thread work 2");
}
}
1This example produces the desired effect, but might not work all the time in the wild: the second thread becomes foreground once the Work method is called. If the first thread yielded, but the QueueUserWorkItem was not serviced, it might never run. |
|