How does multi-threading work in .NET?
By nature and architecture .NET is a multi-threaded environment. There are two main ways of multi-threading which .NET encourages: starting your own threads with ThreadStart delegates, and using the ThreadPool class either directly (using ThreadPool.QueueUserWorkItem) or indirectly using asynchronous methods (such as Stream.BeginRead, or calling BeginInvoke on any delegate). In general, you should create a new thread "manually" for long-running tasks, on the other hand, for short-running tasks, particularly those created often, the thread pool is an excellent choice. The thread pool can run many jobs at once, and uses framework classes internally. In case of Synchronization as there are limited amount of recourses, there can restriction on the access to the resource by one thread at a time. In this situations we can think of implementing locking on the thread. The base class used for threading is System.Threading. All the threads are managed under the Common Language Runtime.
Various action that are taken after the creation of threads are explained in the following sections.
Creating Threads :
Create new instance of Thread object. Thread constructor accepts one parameters which is delegate
Thread dummyThread = new Thread( new ThreadStart(dummyFunction) );
Executing Thread:
To run this thread us the method start provided by Threading namespace
DummyThread.Start ();
Joining Threads:
There is always the requirement to join thread specially when a thread depends on some other thread for completing its task. Lets assume that DummyThread has to wait for DummyPriorityThread to complete its task and then run again. In this case we need to do the following:
DummyPriorityThread.Join() ;
Suspending Thread:
This will suspend the thread for the given number of seconds
DummyPriorityThread.Sleep(<Time in Second>);
Killing Thread:
When there is a need to kill a thread use the following to achieve the same.
DummyPriorityThread.Abort();
Synchronization
There is always a requirement of Synchronization between threads. Following code give some insight of this concept.
using System;
using System.Threading;
namespace SynchronizationThreadsExample
{
class SynchronizationThreadsExample
{
private int counter = 0;
static void Main( )
{
SynchronizationThreadsExample STE = new SynchronizationThreadsExample();
STE.ThreadFunction( );
}
public void ThreadFunction ( )
{
Thread DummyThread = new Thread( new ThreadStart(SomeFunction) ;
DummyThread.IsBackground=true;
DummyThread.Name = "First Thread";
DummyThread.Start( );
Console.WriteLine("Started thread {0}", DummyThread.Name);
Thread DummyPriorityThread = new Thread( new ThreadStart(SomeFunction) );
DummyPriorityThread.IsBackground=true;
DummyPriorityThread.Name = "Second Thread";
DummyPriorityThread.Start( );
Console.WriteLine("Started thread {0}", DummyPriorityThread.Name);
DummyThread.Join( );
DummyPriorityThread.Join( );
}
public void SomeFunction( )
{
try
{
while (counter < 10)
{
int tempCounter = counter;
tempCounter ++;
Thread.Sleep(1);
counter = tempCounter;
Console.WriteLine( "Thread {0}. SomeFunction: {1}",Thread.CurrentThread.Name,
counter);
}
}
catch (ThreadInterruptedException Ex)
{
Console.WriteLine( "Exception in thread {0} ", Thread.CurrentThread.Name);
}
finally
{
Console.WriteLine( "Thread {0} Exiting. ",Thread.CurrentThread.Name);
}
}
}
}
Using Interlock
C# provides a special class called interlocked just for the reason of locking. We can add the following statement example for locking
Interlocked.SomeFunction (ref counter);
Using Locks: This used to lock the critical section of the code and thus help in synchronization. Locking is achieved in following way,
lock (this)
{
Some statements ;
}
Using Monitor
When there is a need to monitor thread we can use the following method,
Monitor.Enter(this);
There are many other methods that are very help in Thread management.
Disadvantage of Threads:
There are some disadvantages of threads also, as mentioned below
- If you have a large number of threads, it can hurt performance, Since the OS switches between them
- More number of threads results in more memory
- Threads can introduce many bugs in the application so should be used carefully
- Thread killing requires lots of post effect information to protect the application
- Usually apartment model the data is shared across the threads, A proper locking system needs to be in place for data sharing