Click here to Skip to main content
Click here to Skip to main content

Understanding Threading in .NET Framework

, 24 Apr 2005
Rate this:
Please Sign up or sign in to vote.
Threading in .NET Framework at a glance.

Summary

This article describes thread basics covering the following areas:

  • How to create a thread; use System.Thread() class and create an instance.
  • How to join a thread; use object.Join() to join threads.
  • How to suspend a thread; use object.Sleep(<No of seconds>) to suspend a thread.
  • How to kill a thread; use object.Abort() to abort a thread.
  • Using Interlocked class which uses Increment and Decrement methods to increment and decrement values.

Thread Synchronization is explained covering the following:

  • Using Locks: allows to mark a lock on the critical section of the code (program), provide synchronization to an object and then to execute the lock in effect.
  • Using Monitor: allows to decide when to enter and exit the synchronization, and it lets us wait for another area of code to become free. Monitor acts as a smart lock on a resource. When we need synchronization, we can call the enter() method of the monitor passing the object we want to monitor. We can explicitly choose the wait() method of the monitor to control thread ordering. In case of using wait(), the waiting threads will be allowed to be notified of a chance to run again if the active thread calls Pulse(). This signals the CLR that there has been a chance in the state that might free a thread that is waiting. The CLR tracks the fact that the earlier thread asked to wait, and the thread will be guaranteed access in the order in which the waits were requested. Exit() can be called once when the thread is finished with the monitor.

Overview

In this article, we are going to look into the basics and advance concepts about Microsoft .NET Framework based Threading support. Refer to the previous article for details about the Microsoft .NET framework.

Threading is one of the integral parts of the Microsoft .NET Framework based Common Language Runtime. Refer to the previous article on .NET Framework for more details.

Architecture of CLR

Threading support is in-built under the Common Language Runtime provided by the Microsoft .NET Framework.

Understanding Threading

  1. Threads are basically light weight processes responsible for multitasking within a single application.
  2. The base class used for threading is System.Threading.
  3. Threads are managed under the Common Language Runtime, programmers don’t have to manage any threads explicitly.
  4. Threads are implemented when you have situations in which you want to perform more then one task at a time.
  5. In case of synchronization, since you have limited amount of recourses, you may have to restrict the access to the resources to one thread at a time. In these situations, you may implement locking on the threading to over come the scenarios.
  6. An apartment is a logical container within a process and is used for objects that share the same thread-access requirement. Objects in the apartment can all receive method calls from any object in any thread in the apartment. And managed objects (object created within CLR) are responsible for thread safety.
  7. Threads can be used under situations where we must wait for an event such as user input, a read from file, or receipt of data over the network.

Working with Threads

Create a new instance of the Thread object. The Thread constructor accepts one parameter that is a delegate. MS CLR provides the ThreadStart delegate class for starting the thread.

Example:

Thread myThread = new Thread( new ThreadStart(myFunc) );

To run this thread, we need the following:

Thread t1 = new Thread( new ThreadStart(Incrementer) );

To instantiate this, we need the following:

t1.Start( );

A detailed example is as below:

namespace Programming_CSharp
{
  using System;
  using System.Threading;
  class Tester
  {
    static void Main( )
    {
      // make an instance of this class
      Tester t = new Tester( );
      // run outside static Main
      t.DoTest( );
    }
    public void DoTest( )
    {
      // create a thread for the Incrementer
      // pass in a ThreadStart delegate
      // with the address of Incrementer
      Thread t1 = new Thread(new ThreadStart(Incrementer) );
      // create a thread for the Decrementer
      // pass in a ThreadStart delegate
      // with the address of Decrementer
      Thread t2 = new Thread(new ThreadStart(Decrementer) );
      // start the threads
      t1.Start( );
      t2.Start( );
    }
    // demo function, counts up to 1K
    public void Incrementer( )
    {
      for (int i =0;i<1000;i++)
      {
        Console.WriteLine("Incrementer: {0}", i);
      }
    }
    // demo function, counts down from 1k
    public void Decrementer( )
    {
      for (int i = 1000;i>=0;i--)
      {
        Console.WriteLine("Decrementer: {0}", i);
      }
    }
  }
}

Output:

Incrementer: 102
Incrementer: 103
Incrementer: 104
Incrementer: 105
Incrementer: 106
Decrementer: 1000
Decrementer: 999
Decrementer: 998
Decrementer: 997

Joining Threads

Once a thread starts running and in some situation if we need to tell the thread to stop processing and wait until a second thread completes processing, we need to join the first thread to the second thread. Use the following for the same. This will join the second thread to the first one.

Example:

t2.Join( );

Suspending the Thread

In some situations, we might want to suspend a running thread.

Example:

t2..Sleep(<No of Seconds>);

Killing a Thread

Threads has to die after the execution of the process in normal situations, occasionally it is required for the programmer to kill a thread. Threads can be killed using the following:

Example:

t2.Abort();

Advanced Threading

Synchronization

In some situations, we need to synchronize the running threads so we can modify the running thread and its resources.

namespace Programming_CSharp
{
  using System;
  using System.Threading;
  class Tester
  {
    private int counter = 0;
    static void Main( )
    {
      // make an instance of this class
      Tester t = new Tester( );
      // run outside static Main
      t.DoTest( );
    }
    public void DoTest( )
    {
      Thread t1 = new Thread( new ThreadStart(Incrementer) );
      t1.IsBackground=true;
      t1.Name = "ThreadOne";
      t1.Start( );
      Console.WriteLine("Started thread {0}",
      t1.Name);
      Thread t2 = new Thread( new ThreadStart(Incrementer) );
      t2.IsBackground=true;
      t2.Name = "ThreadTwo";
      t2.Start( );
      Console.WriteLine("Started thread {0}", t2.Name);
      t1.Join( );
      t2.Join( );
      // after all threads end, print a message
      Console.WriteLine("All my threads are done.");
    }
    // demo function, counts up to 1K
    public void Incrementer( )
    {
      try
      {
        while (counter < 1000)
        {
          int temp = counter;
          temp++; // increment
          // simulate some work in this method
          Thread.Sleep(1);
          // assign the decremented value
          // and display the results
          counter = temp;
          Console.WriteLine("Thread {0}. Incrementer: {1}", 
             Thread.CurrentThread.Name, counter);
        }
      }
      catch (ThreadInterruptedException)
      {
        Console.WriteLine("Thread {0} interrupted! Cleaning up...", 
                          Thread.CurrentThread.Name);
      }
      finally
      {
        Console.WriteLine("Thread {0} Exiting. ", Thread.CurrentThread.Name);
      }
    }
  }
}

Output:

>Started thread ThreadOne
Started thread ThreadTwo
Thread ThreadOne. Incrementer: 1
Thread ThreadOne. Incrementer: 2
Thread ThreadOne. Incrementer: 3
Thread ThreadTwo. Incrementer: 3
Thread ThreadTwo. Incrementer: 4
Thread ThreadOne. Incrementer: 4
Thread ThreadTwo. Incrementer: 5
Thread ThreadOne. Incrementer: 5
Thread ThreadTwo. Incrementer: 6
Thread ThreadOne. Incrementer: 6

Using Interlock

  1. MS CLR provides synchronization tools and mechanisms. This will allow programmers to place locking over running threads.
  2. .NET provides a special class called Interlocked just for the reason of locking. This consists of two methods: Increment and Decrement.

Example:

public void Incrementer( )
{
  try
  {
    while (counter < 1000)
    {
      Interlocked.Increment(ref counter);
      // simulate some work in this method
      Thread.Sleep(1);
      // assign the decremented value
      // and display the results
      Console.WriteLine("Thread {0}. Incrementer: {1}", 
         Thread.CurrentThread.Name, counter);
    }
  }
}

Output (excerpts):

Started thread ThreadOne
Started thread ThreadTwo
Thread ThreadOne. Incrementer: 1
Thread ThreadTwo. Incrementer: 2
Thread ThreadOne. Incrementer: 3
Thread ThreadTwo. Incrementer: 4
Thread ThreadOne. Incrementer: 5
Thread ThreadTwo. Incrementer: 6
Thread ThreadOne. Incrementer: 7
Thread ThreadTwo. Incrementer: 8
Thread ThreadOne. Incrementer: 9
Thread ThreadTwo. Incrementer: 10
Thread ThreadOne. Incrementer: 11
Thread ThreadTwo. Incrementer: 12
Thread ThreadOne. Incrementer: 13
Thread ThreadTwo. Incrementer: 14
Thread ThreadOne. Incrementer: 15
Thread ThreadTwo. Incrementer: 16
Thread ThreadOne. Incrementer: 17
Thread ThreadTwo. Incrementer: 18
Thread ThreadOne. Incrementer: 19
Thread ThreadTwo. Incrementer: 20

Using Locks

A lock marks a critical section of the code, and provides synchronization to an object.

Example:

public void Incrementer( )
{
  try
  {
    while (counter < 1000)
    {
      lock (this)
      {
        int temp = counter;
        temp ++;
        Thread.Sleep(1);
        counter = temp;
      }
      // assign the decremented value
      // and display the results
      Console.WriteLine("Thread {0}. Incrementer: {1}", 
         Thread.CurrentThread.Name, counter);
    }
  }

Using Monitor

There are situations where the programmer need to monitor the running threads, for which we can use the following:

Monitor.Enter(this);

Race Condition and Deadlocks

There are situations when the process goes for a deadlock situation. Synchronization is a little tricky to handle in such cases.

Race Conditions

  1. This situation occurs when success of one program depends on uncontrolled order of execution of certain processes (two independent threads).
  2. We can overcome this situation by using Join() and using Monitor(), Wait() etc…

Deadlocks

In situations when one thread is dependent on another thread's completion, it is some times possible that unknowingly one thread can wait for the other to finish, so the second thread can go ahead and run the second process. In few occasions, each thread may go in a loop to wait for the next thread to complete the processing to start, where both the threads are waiting for each other to complete and none of them is actually doing any processing.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Chandrakant Parmar
Web Developer
Japan Japan
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberJay Nardev(MD Synergy)16-Sep-11 2:07 
GeneralMy vote of 5 PinmemberEric Xue (brokensnow)6-Sep-10 19:44 
GeneralMy vote of 2 Pinmemberraj.kumaarr31-May-10 19:40 
Generalurgent solution needed PinmemberMystic_13-Jul-06 11:44 
i while doing work came up to introducing multi threading in my application but the problem in my case is that the signature of function or functions i want to execute in the thread doesnot match that of delegate "ThreadStart".
those parameter that i pass to my functions r very important i have already spend alots of time finalizing them.
so anyway out??
i will be very thankful for any kind help.
GeneralRe: urgent solution needed Pinmembertermi5-Nov-06 21:14 
QuestionHow to restart the thread PinmemberRizwan Bashir10-Jul-06 2:06 
AnswerRe: How to restart the thread Pinmembertermi5-Nov-06 21:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 25 Apr 2005
Article Copyright 2005 by Chandrakant Parmar
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid