Multithreaded Programming Using C#

Darshana Mihiran Edirisinghe
5 min readOct 10, 2021

--

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.

Synchronous execution

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.

Asynchronous execution

Good to know…

Process

Windows Taks Manager

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.

Synchronous Execution — Example

In the above scenario, In the Main method PrintSecondSection() should wait until the execution finish of the PrintFirstSection() method.

Output

Output console

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.

Multithreaded Execution

Output

Output console

ParameterizedThreadStart delegate

We can use a ParameterizedThreadStart delegate to pass data to the thread function. Let’s say we have a function like below.

Normal function

Then let’s check the signature of the ParameterizedThreadStart delegate.

Signature of 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.

Normal Function

Let’s see how we use the ParameterizedThreadStart delegate. Here we add an object type parameter into the start() method.

start() function

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.

Pass data to the thread function in a typed safe manner

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.

Thread.join()

We can use ‘IsAlive()’ method to check whether the thread function is still executing.

Retrieving data from thread functions

First, create a callback delegate.

Callback delegate

Then create another class to calculate the sum and to call the callback method.

Class to calculate the sum

The below class consumes the above Calculation class.

Let’s look at the completed code.

Complete code — A
Complete code — B

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.

Concurrent access of shared resources

To prevent this, we can use a lock as follows.

Prevent concurrent access of shared resources

--

--

Darshana Mihiran Edirisinghe

Full Stack Developer | Information Technology Consultant | Scrum Master | Tech Enthusiast