GOTCHA 58 Threads from the thread pool are scarce


GOTCHA #58 Threads from the thread pool are scarce

Should you create a thread or use a thread from the thread pool? There are several considerations here.

First, if you create a Thread object, it will start to execute the method of interest within a fairly brief interval (subject to system limitations). In the case of the thread pool, however, you are using shared resources in your process. If another task that uses the thread pool is taking a little longer, your task may get delayed because there is no available thread in the thread pool.

At any given time up to twenty five threads are available per process per processor. You can change this default value at the system level. What does that mean to your application? If your tasks take a short amount of time and you have only a few of them, it is efficient to use the thread pool. However, if your tasks may take an arbitrary amount of time, then using the thread pool may not be a good idea.

Let's get a better understanding of these issues from Example 7-14.

Example 7-14. Using your own thread versus one from thread pool

C# (ThreadFromPool)

 using System; using System.Threading; namespace ThreadPool {     class Test     {         private static void Method1()         {             Console.Write("Executed by Thread {0} which is ",                 AppDomain.GetCurrentThreadId());             if (!Thread.CurrentThread.IsThreadPoolThread)                 Console.Write("not ");             Console.WriteLine("from the thread pool at {0}",                 DateTime.Now.ToLongTimeString());             //Thread.Sleep(10000);         }         [STAThread]         static void Main(string[] args)         {             Console.WriteLine("Using our own thread");             for(int i = 0; i < 5; i++)             {                 new Thread(new ThreadStart(Method1)).Start();                 Thread.Sleep(1000);             }             Console.WriteLine("Press any key to use timer");             Console.ReadLine();             Console.WriteLine("Using timer");             System.Timers.Timer theTimer                 = new System.Timers.Timer(1000);             theTimer.Elapsed                 += new System.Timers.ElapsedEventHandler(                         theTimer_Elapsed);             theTimer.Start();             Thread.Sleep(6000);             theTimer.Stop();         }         private static void theTimer_Elapsed(             object sender, System.Timers.ElapsedEventArgs e)         {             Method1();         }     } } 

VB.NET (ThreadFromPool)

 Imports System.Threading Module Test  Private Sub Method1()  Console.Write("Executed by Thread {0} which is ", _  AppDomain.GetCurrentThreadId())  If Not Thread.CurrentThread.IsThreadPoolThread Then  Console.Write("not ")  End If  Console.WriteLine("from the thread pool at {0}", _  DateTime.Now.ToLongTimeString())  'Thread.Sleep(10000)  End Sub  Public Sub Main()  Console.WriteLine("Using our own thread")  For i As Integer = 0 To 4  Dim aThread As New Thread(AddressOf Method1)  aThread.Start()  Thread.Sleep(1000)  Next  Console.WriteLine("Press any key to use timer")  Console.ReadLine()  Console.WriteLine("Using timer")  Dim theTimer As New System.Timers.Timer(1000)  AddHandler theTimer.Elapsed, _  New System.Timers.ElapsedEventHandler( _  AddressOf theTimer_Elapsed)  theTimer.Start()  Thread.Sleep(6000)  theTimer.Stop()  End Sub  Private Sub theTimer_Elapsed( _  ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)  Method1()  End Sub End Module 

In the previous example, you first run Method1() using threads you create. Then you run the method using a System.Timers.Timer object, which uses a thread from the thread pool. The output from the program is shown in Figure 7-15.

Notice that all the calls to Method1() using the timer were executed by the same thread from the thread pool. Now, what happens if you put a delay in the method? Executing the code after uncommenting Thread.Sleep(10000), you get the output shown in Figure 7-16.

Figure 7-15. Output from Example 7-14


Figure 7-16. Output from Example 7-14 after introducing a delay


Different threads from the thread pool now execute the method. However, the calls to the method using the thread pool are not distributed evenly once per second (note that two calls to Method1() were made at 8:19:48 PM).

Furthermore, let's see what happens if you change Thread.Sleep(10000) to Thread.Sleep(35000) and let the Timer run for more than 35 seconds. Partial output from this change is shown in Example 7-15.

Example 7-15. Partial output upon increasing the delay in Method1()
 Using timer Executed by Thread 2864 which is from the thread pool at 8:21:55 PM Executed by Thread 2196 which is from the thread pool at 8:21:57 PM Executed by Thread 4064 which is from the thread pool at 8:21:57 PM Executed by Thread 1536 which is from the thread pool at 8:21:58 PM Executed by Thread 2492 which is from the thread pool at 8:21:59 PM Executed by Thread 3024 which is from the thread pool at 8:22:00 PM Executed by Thread 2588 which is from the thread pool at 8:22:01 PM Executed by Thread 3000 which is from the thread pool at 8:22:02 PM Executed by Thread 2932 which is from the thread pool at 8:22:03 PM Executed by Thread 3952 which is from the thread pool at 8:22:04 PM Executed by Thread 3004 which is from the thread pool at 8:22:05 PM ... Executed by Thread 2524 which is from the thread pool at 8:22:11 PM Executed by Thread 3016 which is from the thread pool at 8:22:12 PM Executed by Thread 3012 which is from the thread pool at 8:22:13 PM Executed by Thread 3160 which is from the thread pool at 8:22:14 PM Executed by Thread 3156 which is from the thread pool at 8:22:15 PM Executed by Thread 2992 which is from the thread pool at 8:22:16 PM Executed by Thread 3008 which is from the thread pool at 8:22:17 PM Executed by Thread 2984 which is from the thread pool at 8:22:18 PM Executed by Thread 3040 which is from the thread pool at 8:22:19 PM Executed by Thread 2864 which is from the thread pool at 8:22:30 PM Executed by Thread 2196 which is from the thread pool at 8:22:32 PM Executed by Thread 4064 which is from the thread pool at 8:22:32 PM Executed by Thread 1536 which is from the thread pool at 8:22:33 PM Executed by Thread 2492 which is from the thread pool at 8:22:34 PM 

The threads in the thread pool are reused once they become available. This is of course good news. However, notice the lag time between the method executions when all the threads in the thread pool are busy.

IN A NUTSHELL

The thread pool offers a very efficient use of resources, but it should only be used for tasks that are quick and short-lived.

SEE ALSO

Gotcha #50, "Background threads don't terminate gracefully," Gotcha #53, "Environment.Exit() brings down the CLR," Gotcha #59, "Threads invoked using delegates behave like background threads," Gotcha #61, "Exceptions thrown from threads in the pool are lost," and Gotcha #62, "Accessing WinForm controls from arbitrary threads is dangerous."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net