January 17, 2021
Hot Topics:

Multithreading in .NET Applications

  • By Mark Strawmyer
  • Send Email »
  • More Articles »

Using Multiple Threads

There are advantages and disadvantages to the use of multiple threads. Using multiple threads is not always advantageous, so you should make the determination for yourself whether or not there is enough benefit for your application(s).

Advantages of Multiple Threads

  • Improved responsiveness — When it comes to application performance I am a firm believer that perception is reality. If the user perceives that my application is slow, then it that means it is in reality slow. If the application is performing operations that take a perceivably long time to complete, these operations can be put into a separate thread which will allow the application to continue to be responsive to the user.
  • Faster application — Multiple threads can lead to improved application performance. For example, if there are a number of calculations to be performed or the contents of a file are being processed, then there the application can be made faster by performing multiple operations at the same time.
  • Prioritization — Threads can be assigned a priority which would allow higher priority tasks to take precedence over lower priority tasks.

Disadvantages of Multiple Threads

  • Programming and debugging is more complex — With multithreaded applications the programmer must account for race conditions and deadlocks.
  • Threads add overhead to the system — In order for the operating system to track a large number of threads it is going to consume processor time. If there are too many threads then each thread may not be given enough time to execute during its time slice. In addition, each thread is scheduled for execution less frequently due to the volume and time slice committed to each thread.

Threading Example

To demonstrate the use of multiple threads we will use a sample windows application that will show how a user interface can be made to respond differently when performing the same action.

Sample User Interface

The application has a user interface containing a list box. When either the "Run Nonthreaded" or "Run Multithreaded" buttons are pressed the buttons will be temporarily disabled and the list box will be filled with "Hello World" messages. There will be a processing delay thrown in between each entry in the list box. The interface also contains a button to test the interface responsiveness while the list box is being populated. The sample user interface is as follows:

Sample Code Listing

Here is a listing of all of the code behind the user interface. The click events of the "Run Nonthreaded" and "Run Multithreaded" buttons result in the same method being executed. The only difference is that when the "Run Multithreaded" button is pressed the method is executed in a new thread.

using System;using System.Drawing;using System.Collections;using System.ComponentModel;using System.Windows.Forms;using System.Data;namespace CodeGuru.Multithreaded{ /// <remarks> /// Example demonstrating the use of threads in a windows form. /// </remarks> public class Form1 : System.Windows.Forms.Form {   private System.Windows.Forms.Button nonThreadedButton;   private System.Windows.Forms.Button multiThreadedButton;   private System.Windows.Forms.ListBox responseList;   private System.Windows.Forms.Button testResponseButton;   private System.Windows.Forms.Label responseCountLabel;   private System.Windows.Forms.Label responseLabel;   /// <summary>   /// Required designer variable.   /// </summary>   private System.ComponentModel.Container components = null;   public Form1()   {      //       // Required for Windows Form Designer support       //       InitializeComponent();   }   /// <summary>   /// Clean up any resources being used.   /// </summary>   protected override void Dispose( bool disposing )   {      if( disposing )      {         if (components != null)          {            components.Dispose();         }      }      base.Dispose( disposing );   }   #region Windows Form Designer generated code   /// <summary>   /// Required method for Designer support - do not modify   /// the contents of this method with the code editor.   /// </summary>   private void InitializeComponent()   {      this.responseList = new System.Windows.Forms.ListBox();      this.nonThreadedButton = new System.Windows.Forms.Button();      this.multiThreadedButton = new System.Windows.Forms.Button();      this.testResponseButton = new System.Windows.Forms.Button();      this.responseCountLabel = new System.Windows.Forms.Label();      this.responseLabel = new System.Windows.Forms.Label();      this.SuspendLayout();      //       // responseList      //       this.responseList.Name = "responseList";      this.responseList.Size = new System.Drawing.Size(120, 134);      this.responseList.TabIndex = 6;      //       // nonThreadedButton      //       this.nonThreadedButton.Location =                          new System.Drawing.Point(160, 8);      this.nonThreadedButton.Name = "nonThreadedButton";      this.nonThreadedButton.Size = new System.Drawing.Size(120, 23);      this.nonThreadedButton.TabIndex = 1;      this.nonThreadedButton.Text = "Run Nonthreaded";      this.nonThreadedButton.Click += new              System.EventHandler(this.nonThreadedButton_Click);      //       // multiThreadedButton      //       this.multiThreadedButton.Location =                       new System.Drawing.Point(160, 40);      this.multiThreadedButton.Name = "multiThreadedButton";      this.multiThreadedButton.Size = new System.Drawing.Size(120, 23);      this.multiThreadedButton.TabIndex = 3;      this.multiThreadedButton.Text = "Run Multithreaded";      this.multiThreadedButton.Click += new             System.EventHandler(this.multiThreadedButton_Click);      //       // testResponseButton      //       this.testResponseButton.Location =                              new System.Drawing.Point(160, 160);      this.testResponseButton.Name = "testResponseButton";      this.testResponseButton.Size = new System.Drawing.Size(120, 23);      this.testResponseButton.TabIndex = 4;      this.testResponseButton.Text = "Test Responsiveness";      this.testResponseButton.Click += new      System.EventHandler(this.testResponseButton_Click);      //       // responseCountLabel      //       this.responseCountLabel.Location =                          new System.Drawing.Point(112, 160);      this.responseCountLabel.Name = "responseCountLabel";      this.responseCountLabel.Size = new System.Drawing.Size(24, 23);      this.responseCountLabel.TabIndex = 5;      this.responseCountLabel.Text = "0";      //       // responseLabel      //       this.responseLabel.Location = new System.Drawing.Point(8, 160);      this.responseLabel.Name = "responseLabel";      this.responseLabel.TabIndex = 7;      this.responseLabel.Text = "Click Response:";      //       // Form1      //       this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);      this.ClientSize = new System.Drawing.Size(292, 221);      this.Controls.AddRange(new System.Windows.Forms.Control[] {                 this.responseLabel,                 this.responseCountLabel,                 this.testResponseButton,                 this.multiThreadedButton,                 this.nonThreadedButton,                 this.responseList});      this.Name = "Form1";      this.Text = "Multithreaded Example";      this.ResumeLayout(false);   }   #endregion   /// <summary>   /// The main entry point for the application.   /// </summary>   [STAThread]   static void Main()    {      Application.Run(new Form1());   }   /*    * Responde to the nonThreadedButton click event.    */   private void nonThreadedButton_Click(object sender,                                         System.EventArgs e)   {      this.FillList();   }   /*    * Responde to the multiThreadedButton click event.    */   private void multiThreadedButton_Click(object sender,                                           System.EventArgs e)   {      // Launch a thread to do the update      System.Threading.Thread sampleThread =            new System.Threading.Thread(             new System.Threading.ThreadStart(this.FillList));      sampleThread.Start();   }   /*    * Respond to the testResponseButton click event.    */   private void testResponseButton_Click(object sender,                                          System.EventArgs e)   {      this.responseCountLabel.Text =       Convert.ToString(            Convert.ToInt32(this.responseCountLabel.Text) + 1);   }   /*    * Deplay processing for the specificed number of milliseconds    */   private void Delay(int v_MilliSeconds)   {      long startTime = Environment.TickCount;      while( Environment.TickCount — startTime < v_MilliSeconds ) {}   }   /*    * Fill the listbox with hello world buttons.  Pause for a period    * of time between each message.    */   private void FillList()   {      this.responseList.Items.Clear();      this.responseCountLabel.Text = "0";      this.ToggleButtons(false);      for( int i = 0; i < 10; i++ )      {         responseList.Items.Add("Hello World #" + i);         this.Delay(1000);      }      this.ToggleButtons(true);   }   /*    * Toggle the form buttons on or off accordingly.    */   private void ToggleButtons(bool v_Toggle)   {      this.nonThreadedButton.Enabled = v_Toggle;      this.multiThreadedButton.Enabled = v_Toggle;   } }}

Testing the Sample

Run the sample application and press the "Run Nonthreaded" button. While the process is running try pressing the "Test Responsiveness" button. You'll notice the user interface is not updating the list as items are added, nor is the response counter updated when you test the responsiveness. Once processing is complete, the list box will populate and the test responsiveness actions will be executed.

Now press the "Run Multithreaded" button. While the process is running you'll immediately notice that the list box is updating as the process executes. As you press the "Test Responsiveness" button you will notice the button is responsive and the counter updates as you click on the button. This clearly shows how using threads can allow our application to be more responsive in certain scenarios.

Page 2 of 3

This article was originally published on May 7, 2003

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date