C# Multithreading
ThreadA thread is defined as the execution path of a program. Each thread defines a unique control flow. If your application involves complex and time-consuming operations, it is often beneficial to set up different thread execution paths, with each thread performing specific work.
Thread isLightweight processA common example of using threads is the implementation of parallel programming in modern operating systems. Using threads saves the waste of CPU cycles and improves the efficiency of applications.
The programs we have written so far run as a single process with a single thread as the running instance of the application. However, in this way, the application can only execute one task at a time. To execute multiple tasks simultaneously, it can be divided into smaller threads.
Thread lifecycle
The thread lifecycle begins when an object of the System.Threading.Thread class is created, and ends when the thread is terminated or completes execution.
The various states in the thread lifecycle are listed below:
- Unstarted state: The state when a thread instance has been created but the Start method has not been called.
- Ready state: The state when a thread is ready to run and is waiting for a CPU cycle.
- Non-runnable state: A thread is not runnable in the following cases:
- The Sleep method has been called
- The Wait method has been called
- Blocked by an I/O operation
- Dead state: The state when the thread has completed execution or has been aborted.
main thread
In C#,System.Threading.ThreadThe Thread class is used for thread work. It allows you to create and access individual threads in a multithreaded application. The first thread executed in a process is called the main thread.main thread。
When a C# program starts execution, the main thread is automatically created. UsingThreadThreads created by the class are called child threads of the main thread. You can use the Thread class'sCurrentThreadProperty access thread.
The following program demonstrates the execution of the main thread:
Example
using System.Threading;
namespace MultithreadingApplication
{
class MainThreadProgram
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following results:
This is MainThread
Common properties and methods of the Thread class
The table below listsThreadSome common methods of the classProperty:
| Property | Description |
|---|---|
| CurrentContext | Gets the current context in which the thread is executing. |
| CurrentCulture | Gets or sets the culture of the current thread. |
| CurrentPrincipal | Gets or sets the current principal of the thread (for role-based security). |
| CurrentThread | Get the currently running thread. |
| CurrentUICulture | Gets or sets the current culture used by the Resource Manager to look up culture-specific resources at run time. |
| ExecutionContext | Gets an ExecutionContext object that contains contextual information about the current thread. |
| IsAlive | Gets a value that indicates the execution status of the current thread. |
| IsBackground | Gets or sets a value indicating whether a thread is a background thread. |
| IsThreadPoolThread | Gets a value indicating whether a thread belongs to the managed thread pool. |
| ManagedThreadId | Gets the unique identifier of the current managed thread. |
| Name | Gets or sets the name of the thread. |
| Priority | Gets or sets a value indicating the scheduling priority of the thread. |
| ThreadState | Gets a value that contains the state of the current thread. |
The table below listsThreadSome common methods of the classMethods:
| Serial Number | Method name & Description |
|---|---|
| 1 | public void Abort() Raises a ThreadAbortException on the thread on which this method is called, to begin the process of terminating this thread. Calling this method usually terminates the thread. |
| 2 | public static LocalDataStoreSlot AllocateDataSlot() Allocates an unnamed data slot on all threads. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 3 | public static LocalDataStoreSlot AllocateNamedDataSlot(
string name)
Allocates a named data slot on all threads. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 4 | public static void BeginCriticalRegion() Notifies the host that execution is about to enter a region of code in which the effects of thread aborts or unhandled exceptions may jeopardize other tasks in the application domain. |
| 5 | public static void BeginThreadAffinity() Notifies the host that managed code is about to execute instructions that depend on the identity of the current physical operating system thread. |
| 6 | public static void EndCriticalRegion() Notifies the host that execution is about to enter a region of code in which thread aborts or unhandled exceptions affect only the current task. |
| 7 | public static void EndThreadAffinity() Notifies the host that managed code has finished executing instructions that depend on the identity of the current physical operating system thread. |
| 8 | public static void FreeNamedDataSlot(string name) Eliminates the association between names and slots for all threads in the process. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 9 | public static Object GetData(
LocalDataStoreSlot slot
)
Retrieves the value from the specified slot on the current thread, within the current domain of the current thread. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 10 | public static AppDomain GetDomain() Returns the current domain in which the current thread is running. |
| 11 | public static AppDomain GetDomainID() Returns a unique application domain identifier. |
| 12 | public static LocalDataStoreSlot GetNamedDataSlot(
string name
)
Looks up a named data slot. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 13 | public void Interrupt() Interrupts a thread that is in the WaitSleepJoin thread state. |
| 14 | public void Join() Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage message pumping. This method has different overload forms. |
| 15 | public static void MemoryBarrier() Synchronizes memory access as follows: the processor executing the current thread cannot reorder instructions in such a way that memory accesses after the MemoryBarrier call execute before memory accesses prior to the MemoryBarrier call. |
| 16 | public static void ResetAbort() Cancels the Abort requested for the current thread. |
| 17 | public static void SetData(
LocalDataStoreSlot slot,
Object data
)
Sets data in the specified slot on the currently running thread for the thread's current domain. For better performance, use fields marked with the ThreadStaticAttribute attribute instead. |
| 18 | public void Start() Start a thread. |
| 19 | public static void Sleep(
int millisecondsTimeout
)
Pauses the thread for a period of time. |
| 20 | public static void SpinWait(
int iterations
)
Causes a thread to wait for the amount of time defined by the iterations parameter. |
| 21 | public static byte VolatileRead(
ref byte address
) public static double VolatileRead( ref double address ) public static int VolatileRead( ref int address ) public static Object VolatileRead( ref Object address ) Reads the field value. Regardless of the number of processors or the state of the processor cache, the value is the latest value written by any processor in the computer. This method has different overload forms. Only some forms are given here. |
| 22 | public static void VolatileWrite(
ref byte address,
byte value
) public static void VolatileWrite( ref double address, double value ) public static void VolatileWrite( ref int address, int value ) public static void VolatileWrite( ref Object address, Object value ) Immediately writes a value to a field so that the value is visible to all processors in the computer. This method has different overload forms. Only some forms are given here. |
| 23 | public static bool Yield() Causes the calling thread to execute another thread that is ready to run on the current processor. The thread to be executed is selected by the operating system. |
Creating Threads
Threads are created by extending the Thread class. The extended Thread class callsStart()method to start the execution of the child thread.
The following program demonstrates this concept:
Example
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following results:
In Main: Creating the Child thread Child thread starts
Manage Threads
The Thread class provides various methods for managing threads.
The following example demonstratessleep()Use of the method to suspend a thread for a specified amount of time.
Example
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
// Pause the thread for 5000 milliseconds
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds",
sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following results:
In Main: Creating the Child thread Child thread starts Child Thread Paused for 5 seconds Child thread resumes
Destroying Threads
Abort()method is used to destroy the thread.
By throwingthreadabortexceptionAborts the thread at run time. This exception cannot be caught. If there is afinallyblock, control is transferred tofinallyBlock.
The following program illustrates this:
Example
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// Count to 10
for (int counter = 0; counter <= 10; counter++)
{
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
}
catch (ThreadAbortException e)
{
Console.WriteLine("Thread Abort Exception");
}
finally
{
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args)
{
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
// Pause the main thread for a period of time
Thread.Sleep(2000);
// Now abort the child thread
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following results:
In Main: Creating the Child thread Child thread starts 0 1 2 In Main: Aborting the Child thread Thread Abort Exception Couldn't catch the Thread Exceptionother extensions