In c#, the thread is a basic unit of execution within the process, and it is responsible for executing the application logic.
By default, every application or program will carry one thread to execute the application logic, and that thread is called the Main thread. So, we can say that every program or application is by default a single-threaded model.
For example, in a Windows operating system, if we open Microsoft Excel and Word applications simultaneously, each application process will be taken care of by separate threads.
In c#, we need to import System.Threading
namespace in our program to work with threads. Once we import System.Threading
namespace, we can create or access the threads using Thread
class.
Generally, in c# when we start a program execution, the Main thread will automatically create to handle the program logic. If we create any other threads in our program by using Thread
class those will become child threads for the Main thread.
If we want to access the Main thread that is executing the current program code, we can get it by using CurrentThread
property of the Thread
class.
Following is the example of getting the main thread details using CurrentThread
property of Thread
class.
If you observe the above code, we imported System.Threading
namespace to get the main thread details by using CurrentThread
property of Thread
class.
When we execute the above program, we will get the result below.
This is how we can access our application's main thread, which executes our program code based on our requirements.
In c#, the Main thread is responsible for executing the programming logic in a synchronous way that means one after another. If we want to execute a few tasks simultaneously (asynchronous way), we need to create the child threads in our application.
In c#, we can create a thread by extending the Thread
class. To create a new thread, we need to pass ThreadStart
delegate as a parameter to the Thread constructor, as shown below. Here, the parameter ThreadStart
is the method executed by the new thread.
Once the thread is created, we need to call the Start
method of Thread
class to start the execution of the newly created thread.
Here, PrintInfo is the method, and it will be executed when we start the newly created thread. Initially, when we create a thread that will be in the unstarted state, so we need to start the thread by using Start()
method.
As we discussed, if we create any threads in our program by using Thread
class those will become child threads for the Main thread.
Following is the example of creating the thread in c# using Thread
class.
When we execute the above program, we will get the result below.
The above result shows that the Main thread and child thread started their execution simultaneously. The child thread continued its execution until it finished its task even after completion of the Main thread execution.
The following table lists some of the most commonly used properties of Thread
class to work with threads in c#.
Property | Description |
---|---|
CurrentContext | It will return the current context in which the thread is executing. |
CurrentThread | It will return the currently running thread. |
CurrentCulture | It is useful to get or set the culture for the current thread. |
CurrentUICulture | It is useful to get or set the Resource Manager's current culture to look up culture-specific resources at run time. |
IsAlive | It is useful to get the execution status of the current thread. |
IsBackground | It is useful to get or set a value that indicates whether the thread is a background thread or not. |
IsThreadPoolThread | It will return a value that indicates whether the thread belongs to the managed thread pool or not. |
ManagedThreadId | It will return a unique identifier of the currently managed thread. |
Name | It is useful to get or set the name of the thread. |
Priority | We can get or set a value that indicates the scheduling priority of a thread. |
ThreadState | It is useful to get the state of the current thread. |
The following table lists some of the most commonly used methods of Thread
class to work with threads in c#.
Method | Description |
---|---|
Abort() | This method is useful to terminate the thread. |
AllocateDataSlot() | It will allocate an unnamed data slot on all the threads. |
AllocateNamedDataSlot() | It will allocate a named data slot on all threads. |
BeginThreadAffinity() | It will notify a host that the managed code is about to execute the instructions that depend on the identity of the current physical operating system thread. |
EndThreadAffinity() | It will notify a host that the managed code has finished executing the instructions that depend on the identity of the current physical operating system thread. |
Equals() | It will determine whether the specified object is equal to the current object or not. |
Finalize() | It will ensure that the resources are freed and other cleanup operations are performed when the garbage collector reclaims the Thread object. |
GetData() | It is useful to retrieve the value from the specified slot on the current thread. |
GetDomain() | It will return the current domain in which the current thread is running. |
GetHashCode() | It will return the hash code of the current thread. |
GetType() | It will return the type of current instance. |
Interrupt() | It will interrupt a thread that is in the WaitSleepJoin thread state. |
Join() | It will make the thread finish its work or halt other threads until it completes work. |
Resume() | It will resume a thread that has been suspended. |
Sleep() | It will suspend the current thread for a specified amount of time. |
Start() | It will instruct the operating system to change the state of the current instance to Running. |
Suspend() | It will suspend the thread. |
VolatileRead() | It will read the value of a field, and that value is the latest written by any processor in a computer. |
VolatileWrite() | It will write a value to the field immediately so that the value will be visible for all processors in the computer. |
Yield() | It will yield the execution to another thread that is ready to run on the current processor. |
In c#, each thread will have a life cycle, and it will start when we create an instance of the object using Thread
class. Once the task execution of the thread is completed, then the life cycle of the thread will end.
At any point, the thread in c# will exist in any one of the following states.
State | Description |
---|---|
Unstarted | When we create the thread, that will be in the unstarted state. |
Runnable | When we call the Start() method, the thread will move to ready to run or runnable state. |
Running | It indicates that the thread is in a running state. |
Not Runnable | If the thread is in a not runnable state means there is a chance that the Sleep() or Wait() or Suspend() method is called on the thread or blocked by I/O operations. |
Dead | If the thread is in a dead state, it means the thread completes its task execution or is aborted. |
Following is the example of knowing the lifecycle and states of thread in c#.
If you observe the above example, we used ThreadState
property of Thread
class to know the state of the thread, and we used Start()
, Suspend()
, and Resume()
methods of Thread
class to start, suspend and resume the execution of a thread.
When you execute the above program, you will get the result below.
This is how we can change or vary the thread states in our application based on requirements.
Following is the example of managing the thread by using various methods of Thread
class.
If you observe the above example, we used different methods (Start, Join, and Sleep) of the Thread class to manage the thread, and the Stopwatch functionality is used to calculate the thread execution time based on our requirements.
Here, we used Start() method to start the thread execution, the Join() method to halt the execution till the thread execution is completed, and the Sleep() method is used to pause the thread execution for 4 seconds.
When you execute the above program, you will get the result below.
This is we can manage the thread execution by using Thread class methods based on our requirements.
In c#, by using the Abort() method of the Thread class, we can end or abort the thread execution process. While terminating the threading process, the Abort() method will raise a ThreadAbortException in the thread on which it is invoked.
Following is the example of terminating the thread execution process in c#.
In c#, we have two types of threads are available, those are
As discussed, our program code execution will be taken care of by the Main thread. If we create new threads to execute some of the methods, those will become child threads for the Main thread, and our application will become a multithreaded application.
Foreground threads are the threads that will run until it finishes their work, even if the Main thread completes its process. So, the lifespan of foreground threads will not depend on the Main thread.
Following is the example of foreground threads in c#.
The above example shows that we created a new child thread (t1) and executed the PrintInfo method. In PrintInfo method, every time we are pausing the thread execution for 2 seconds using the Sleep method.
When you execute the above program, you will get the result below.
Child Thread Execution Completed
If you observe the above result, even after completion of Main thread execution, the child thread continued its execution and completed its work.
In c#, background threads are just the opposite of foreground threads. The background threads will quit their process immediately when the Main thread quits. Here, the lifespan of background threads will depend on the Main thread.
To make the thread a background thread, we need to set IsBackground
property to true
for that thread. Background threads are useful for any operation that should continue as long as an application is running, but these will not prevent the application from terminating.
Following is the example of creating a background thread by setting IsBackground
property to true
in c#.
If you observe the above example, we created a new child thread (t1) and set IsBackground property to true to make the child thread (t1) a background thread.
When you execute the above program, you will get the result below.
If you observe the above result, the child thread process quits immediately after completion of the Main thread execution.
The following are the important points that you need to remember about threads in c#.
System.Threading
namespace in our program. System.Threading
namespace in our program, we can create or access the threads using the Thread class.In the following chapters, we will learn more about using multiple child threads with examples.