Friday, March 26, 2010

Code: C# Simple Multithreading Example using ThreadPool

Below you will find a simple, complete code sample for multithreading in C# using the ThreadPool class.  This sample uses a simple counter to track the number of threads that are active to prevent the application from closing before all threads have completed.  Although there are other ways to force a method to wait for all threads to complete before exiting, using a static counter allows you to create a separate method to determine when the application is allowed to exit.  This is useful for handling OnStop events on windows services.  Within the StopProcessing() method you could also set a flag that would prevent your application from creating new threads.

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6.  
  7. namespace MultiThreadedApp
  8. {
  9.     class Program
  10.     {
  11.         static int _threadCounter = 0;
  12.  
  13.         static void Main(string[] args)
  14.         {
  15.             for (int i = 0; i < 10; i++)
  16.             {
  17.                 CreateThread(i);
  18.             }
  19.  
  20.             StopProcessing();
  21.  
  22.             Console.WriteLine("Finished");
  23.         }
  24.  
  25.         private static void CreateThread(int threadId)
  26.         {
  27.             Console.WriteLine("Creating Thread {0}", threadId);
  28.             MethodParameters newParameter = new MethodParameters();
  29.             newParameter.ThreadId = threadId;
  30.             newParameter.ThreadCreated = DateTime.Now;
  31.             Interlocked.Increment(ref _threadCounter);
  32.             ThreadPool.QueueUserWorkItem(new WaitCallback(LongRunningProcess), (object)newParameter);
  33.         }
  34.  
  35.         private static void LongRunningProcess(object input)
  36.         {
  37.             MethodParameters inputParams = (MethodParameters)input;
  38.             Random random = new Random(((MethodParameters)input).ThreadId);
  39.             Thread.Sleep(random.Next(500, 5000));
  40.             Console.WriteLine("Thread {0} complete in {1} seconds", inputParams.ThreadId,
  41.                 (DateTime.Now - inputParams.ThreadCreated).TotalSeconds);
  42.  
  43.             Interlocked.Decrement(ref _threadCounter);
  44.         }
  45.  
  46.         private static void StopProcessing()
  47.         {
  48.             Console.WriteLine("Waiting for {0} threads to complete", _threadCounter);
  49.             while (_threadCounter > 0)
  50.                 Thread.Sleep(500);
  51.         }
  52.  
  53.         private class MethodParameters
  54.         {
  55.             public DateTime ThreadCreated { get; set; }
  56.             public int ThreadId { get; set; }
  57.         }
  58.     }
  59. }