Multithreading - C# Programming for Beginners (2015)

C# Programming for Beginners (2015)

Chapter 10: Multithreading

Up until this point, we have been working with single-threaded applications where program follow a single path of execution and only a single piece of code is executed at a particular time. This approach is suited to simple console based applications. However, in case of advanced GUI based applications, a single-threaded execution causes unresponsiveness and delayed execution. Consider a Windows form application where data has to be fetched before being displayed on the form. During the period when data is being fetched by the application, the user can do nothing on the front end of the form. If the database is huge, more time is spent fetching the data causing the front end of the application to behave unresponsively. Multithreading is the solution to such problems. In this chapter, we are going to study how to create threads and how they work together resulting in asynchronous program execution.

Contents

· What is a thread?

· Thread Creation in C#

· Thread Join and Sleep

1- What is a thread?

A thread is the smallest unit of execution. A thread runs inside a process. A process reserves operating system resources along with an exclusive execution environment. One process can have one or more threads. In single-threaded applications, only one thread runs inside a process, having exclusive access to all the process resources and the execution environment. In case of multithreaded applications, multiple threads run inside a process and they share several process resources, particularly memory and the execution environment. This sharing of resources leads to the solution of the unresponsiveness problem explained in the introduction. In multithreaded applications, one thread can fetch data from the database and store it in the shared memory, and the second thread can simultaneously display the fetched data on the front end of the application.

2- Thread Creation in C#

Creating a thread in C# is an extremely straight forward process. You just have to create an object of the “Thread”. In the “Thread” class constructor, pass the method delegate that you want to run in a separate thread. Next, simply call the “Start” method on the object which you created. The first example of this chapter demonstrates thread creation and the execution process in detail. Have a look at it.

Example1:

using System;

usingSystem.Threading;

namespaceMyCSharpApplication

{

class Program

{

static void Main(string[] args)

{

Thread t1 = new Thread(DisplayTwo);

Thread t2 = new Thread(DisplayThree);

t1.Start();

t2.Start();

for (inti = 0; i< 100; i++)

{

Console.Write("1");

}

Console.Read();

}

static void DisplayTwo()

{

for (inti = 0; i< 100; i++)

{

Console.Write("2");

}

}

static void DisplayThree()

{

for (inti = 0; i< 100; i++)

{

Console.Write("3");

}

}

}

}

To perform threading related tasks in your program, you need to import “System” and “System.Threading” namespace in your code. C# runtime creates one thread by default for every program. This is the thread in which the “Main” method runs. In Example2, inside the “Main” method, we have created two objects of “Thread” class. These objects have been named t1, and t2. In the constructor of the first object, t1, we passed the “DisplayTwo” method delegate. This method displays the digit “2” one hundred times on console. This method has been defined immediately after the “Main”. Similarly, in the constructor of the t2 object, the “DisplayThree” method has been called. This method displays the digit “3” one hundred times on the screen. After initializing t1 and t2 inside the “Main” method, the “Start” method has been called on this object. Calling “Start” on the thread object creates a new path of execution which runs parallel to already-executing threads. At this point in time, three threads are running simultaneously: The main thread (which is running the “Main” method) and the t1 and t2 threads (which are running “DisplayTwo” and “DisplayThree” methods). This means that now we have three execution paths which are being executed simultaneously. These three paths are simultaneously trying to print the digits “1”, “2”, and “3” on the screen, one hundred times each. The output of the code in Example1 is as follows:

Output1

321231231313132133332212312133223122332213223121121212131313111121223333123123132323212232121233223112332133123122321322312113232122312332212121113132121312332213213322312233213322313122223312332212331321233121212311123212221313233211322312233213322123321232212213331311313131131331333131111111111111

On the console screen, you will see that these digits are printed in a random order, although we called the “DisplayTwo” method first and then “DisplayThree”. This is because all the threads are simultaneously trying to access the output console and print their respective digit; since control can only be accessed by one thread a time, it is randomly being allotted to each thread, resulting in a random display of digits on the output screen.

3- Thread Join and Sleep

In the previous section, we studied how multiple threads execute simultaneously. What if you want to let one thread complete its execution before proceeding further? To wait for an object to complete its execution, you call the “Join” method on that object. Similarly, if you want to stop thread execution for a particular time period, you can call the “Sleep” method on the thread class. This method takes times in milliseconds, or “TimeSpan” object, as its parameter.

To see this concept in action, have a look at the second example.

Example2:

using System;

usingSystem.Threading;

namespaceMyCSharpApplication

{

class Program

{

static void Main(string[] args)

{

Thread t1 = new Thread(DisplayTwo);

t1.Start();

t1.Join();

Console.WriteLine("\n==========================================");

for (inti = 0; i< 100; i++)

{

Console.Write("1");

if (i+1 == 50)

{

Console.WriteLine("\nThread Sleeps here for 5 seconds...");

Thread.Sleep(5000);

}

}

Console.Read();

}

static void DisplayTwo()

{

for (inti = 0; i< 100; i++)

{

Console.Write("2");

}

}

}

}

In Example2, we created thread object t1 which runs the “DisplayTwo” method. We start the thread execution by calling “Start” on this object. Immediately after calling “Start”, we called “Join” on the t1 object in the next line. At this point, the thread inside which “Join” is called waits for the completion of the thread on which “Join” is called. This means that the “Main” method will wait for the complete execution of the t1 thread before executing itself further. After the t1 thread executes, the “Main” method will execute and the “for loop”, which prints the digit “1”, will also execute. When the “for loop” is executed 50 times, we call “Sleep” for 5 seconds. (5000 ms = 5 sec). The thread takes a break for 5 seconds and then prints the remaining digits. The output of the code in Example2 is as follows:

Output2:

2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

==========================================

11111111111111111111111111111111111111111111111111

Thread Sleeps here for 5 seconds...

11111111111111111111111111111111111111111111111111

Exercise 10

Task:

Create two threads inside the “Main” method. One thread should call a method which displays “+” on console one hundred times. The other method should display “X” on the screen one hundred times. The “Main” method should wait for the completion of both of these threads, and then it should display “#” on the screen 20 times. It should then wait for 3 seconds before displaying “#” again, this time 60 times. Finally, it should wait for 3 more seconds before displaying “#” 20 more times.

Solution

using System;

usingSystem.Threading;

namespaceMyCSharpApplication

{

class Program

{

static void Main(string[] args)

{

Thread t1 = new Thread(DisplayPlus);

Thread t2 = new Thread(DisplayMultiply);

t1.Start();

t2.Start();

t1.Join();

t2.Join();

Console.WriteLine("\n==========================================");

for (inti = 0; i< 100; i++)

{

Console.Write("+");

if (i+1 == 20)

{

Console.WriteLine("\nThread Sleeps here for 3 seconds...");

Thread.Sleep(3000);

}

if (i + 1 == 80)

{

Console.WriteLine("\nThread Sleeps here for 3 seconds...");

Thread.Sleep(3000);

}

}

Console.Read();

}

static void DisplayPlus()

{

for (inti = 0; i< 100; i++)

{

Console.Write("+");

}

}

static void DisplayMultiply()

{

for (inti = 0; i< 100; i++)

{

Console.Write("X");

}

}

}

}