Screenshot - form1Threads.jpg

Introduction

Threads enable execution of different pieces of code at the same time. You may encounter the terms: synchronous, sequential or procedural execution, all describing the execution of code one command at a time (like one big queue). On the other hand, asynchronous and concurrent or parallel execution uses threads to execute pieces of code at the same time, under the same process.

Quick Peek Under the Hood

The definition same time from the introduction is a little misleading, because you actually can't achieve 100% parallel execution in single processor architecture. In order to simulate parallel execution, C# uses a timing mechanism that allows each thread to start at a certain interval (in 10' milliseconds), and continue with a different thread, and then to go back again to the first thread at a certain interval. This looks like parallel execution and is known as "time slicing". It is being done behind the scenes by the thread scheduler function.

What For?

So why do we need it in the first place? Well most of the time, you actually won't use threads and you will do fine without them, but when the time comes when the application is required to perform few tasks at the same time, you will look at how to implement threads. Simple examples are programs that give you indication of a task progress. In general, programs that use time consuming tasks in the background are considered good candidates for threads driven code. You can present the user with a progress bar while the task is being processed in the background and ease his waiting time.
When you move files from one location to another, there is a progress bar presenting how much time is left for the task to complete. Those types of programs use two threads, one to execute the main task like moving files from one location to another, and a second thread that checks the destination location of the file and calculates how many bytes were transferred and the time left to complete the task.
In the past, I used threads when I needed to create a search engine for a tourist company that enabled users to book airline tickets online. After the user entered the departure, destination and dates, the search engine had to start sending the request to different airline companies. Each airline company had its own service that processed the request and sent back the results of available places in the flight. However the time it took to collect all the results from all three different airliners was unacceptable. So in order to speed up the process, we divided the search operation into different threads, each one activates a different airline service and we presented users with the results as they came.

Key Points

Every C# Program Starts with a Single Thread

The main() method is known to be the starting point of a C# application and therefore it is the main thread.

Global Static and Instant Variables are Shared between the Threads

If you declared a class that uses different threads, they will all have access to the class variables.

Each Thread has its Own Copy of the Delegate Method Variables

If we have two threads calling the same method, each thread will hold a copy of the instant variable of the method. This means that if we have variable x=1 in one thread, it will not change the value if x=8 in the other thread, as long as x is declared inside the delegate method.

Threads Safety or Not

The advantage of using threads comes with a cost of variable or data safety. Because two threads can access a global variable at the same time, one process can change the variable while the second variable still has a copy of the variable value before it was changed by the first thread.
For example, let's say we have a global variable with the value 1. We have two threads that use the same simple method change():
Private void change (){
If (globalVaribleA == 1){
Command1();
A=2;
}
}
The problem is that if the two threads execute this method at the same time, there might be a chance that one of the threads will change the value to 2 while the other thread still sees A as equal to 1, and will execute command1() even though it no longer agrees with the rule of A==1.
For any of you that use databases, 10 people can access the same record at the same time (with the use of threads), each one changes the same record without the other knowing about it. This is why we need to use the lock statement that will lock the record or data to a single thread at a time.

Threads and Processes

Some refer to threads as the lightweight version of a process. The reason for this is that a process has its own private space with its own private resources, while threads are contained inside a process and share resources with other threads.

Name your Threads

It is a good practice to name the threads to enable debugging and plotting the thread names running in a given point of time.

Foreground and Background Threads

Default threads are in a foreground state; as long as they are active, the application will run, meaning they keep the application alive. On the other hand, background threads when terminated will end the application if they are the last tasks. If you leave a thread in the background, the application can't exit.

Priority

Try to avoid setting the priority to high as it can halt the system in some cases.

Exceptions

Exception should be handled only at the thread level meaning inside the method and not in the outer class.

The Code

The code sample attached can be used as a starting point for using threads. The program creates three threads running simultaneously and presents a counter and a progress bar of each thread. The code is simple with remarks for each step.
Here is the open Thread code. Please note that thread1-3 are simple methods in the page class that will increase a counter and present the progress with the use of the progress bar and a counter.
// create thread1
ThreadStart newThread1 = new ThreadStart(thread1);
Thread t1 = new Thread(newThread1);
t1.Start();
// create thread2
ThreadStart newThread2 = new ThreadStart(thread2);
Thread t2 = new Thread(newThread2);
t2.Start();
// create thread3
ThreadStart newThread3 = new ThreadStart(thread3);
Thread t3 = new Thread(newThread3);
t3.Start();