Multithreaded Programming Using C#
Introduction
Execution of the program or a code segment is always been executed in two ways.
Synchronous way
In a synchronous way, multiple code segments are executed one after the other.
Asynchronous way
In an asynchronous way, multiple code segments are executed in a parallel way. Doesn’t need to wait till the execution of the one code segment to start the execution of another code segment.
Good to know…
Process
The operating system uses ‘Process’ to facilitate the execution of a program by proving the resource required. Each process has a unique process id with it. By using the windows task manager you can view the processes in which a program is being executed.
Tread
A process should have at least one thread to execute the application code. It is commonly known as ‘Main Thread’. Let’s look at the following scenario without multithreading.
In the above scenario, In the Main method PrintSecondSection() should wait until the execution finish of the PrintFirstSection() method.
Output
If both methods are independent of each other we can execute this in a multithreaded way to reduce the execution time. To implement multithreading, we can create a thread in the main class as follows. Therefore PrintFirstSection() method will execute in the main thread and the PrintFirstSection() method will execute in the worker thread that we created. Creating a thread does not start the execution of it. Therefore need to start the thread as well.
Output
ParameterizedThreadStart delegate
We can use a ParameterizedThreadStart delegate to pass data to the thread function. Let’s say we have a function like below.
Then let’s check the signature of the ParameterizedThreadStart delegate.
According to the Visual Studio Intellisense, the ParameterizedThreadStart delegate return type is void and it supports only object type parameters. Therefore, we have to change the current function signature of the print function to as same as the delegate signature.
Let’s see how we use the ParameterizedThreadStart delegate. Here we add an object type parameter into the start() method.
Good to know…
In the above code segment, using ParameterizedThreadStart delegate and Thread.Start(object) method to pass data to the thread function is not type-safe. Therefore, we are losing the type of safety.
To pass data to the thread function in a typed safe manner, we can encapsulate the thread function and the data as follows.
Thread.join
Thread class provides the Join() method which allows one thread to wait until another thread completes its execution. If it is a Thread object whose thread is currently executing, then t.Join() causes the current thread to pause its execution until the thread it joins completes its execution.
In some scenarios, let’s say in a class we have two thread functions and we need these two thread function values for further calculations, then we need to pause the execution of the main threat till the completion of the execution of both threads.
We can use ‘IsAlive()’ method to check whether the thread function is still executing.
Retrieving data from thread functions
First, create a callback delegate.
Then create another class to calculate the sum and to call the callback method.
The below class consumes the above Calculation class.
Let’s look at the completed code.
Prevent concurrent access of shared resources in multithreading
By using the Lock keyword ensures that one thread is executing a piece of code at one time. The lock keyword ensures that one thread does not enter a critical section of code while another thread is in that critical section.
Let’s take an example. Within the main method, we create 3 threads and execute the CalculateResuls() function. Every time we run this, we get different outputs because the total field is a shared resource and it is not protected from the concurrent access from the multiple threads.
To prevent this, we can use a lock as follows.