Chapter 2 – Threading Classes by muskad202

The Thread Class:

Once you’ve decided what work needs to be done in a separate thread by your application, you need to create an object of the Thread class.

The Thread class is used for creating threads, controlling them, and for terminating them. I’ll show you how to use this class for creating a thread after we discuss the ThreadStart delegate.

As mentioned in Chapter 1, every piece of code that executes within your application does so within the context of a thread. If you don’t create multiple threads from your code, then your entire code runs within a single thread (usually – the exceptions are the cases where you might call functions within the .NET or other libraries which then create their own threads). We’ll write a simple application that prints out information regarding the thread that is currently executing.

Start Visual Studio, and create a new Console Application. Within the main function, add the following lines:

Thread thisThread = Thread.CurrentThread;

Console.WriteLine(“The ID of the current thread is : “ + thisThread.ManagedThreadId);

Console.WriteLine(“The State of the current thread is : “ + thisThread.ThreadState.ToString());

Console.WriteLine(“Is this thread a background thread? : “ + thisThread.IsBackground.ToString()); 

You will need to add a

using System.Threading;

statement in order for the code to compile correctly. Most of the Threading related classes appear within this namespace.

Compile and run the project, you should obtain output similar to the following:

The Thread ID of the currently running thread is 1. This is expected, since you only have one thread in your application – the default thread. You also see that the state of the currently running thread is “Running”. At any point of time, a thread can be in one of the following states:

 

  • StopRequested – someone has requested that this thread be stopped. SuspendRequested – someone has requested that this thread be paused (suspended).
  • Running
  • Background – this thread is a background thread. Background threads are threads that do not prevent a process from terminating. A process will keep on running until all Foreground threads have completed. Unstarted
  • Stopped WaitSleepJoin – this thread is currently waiting for another thread to complete.
  • Suspended AbortRequested – someone has requested this thread to be terminated (aborted).
  • Aborted

 

Thread thisThread = Thread.CurrentThread;

The Thread class exposes a static variable called CurrentThread. You can always use this variable to obtain the thread object that represents the currently running thread.

Let’s now see how we can create a new thread. 

The ThreadStart Delegate:

When you create a thread, you need to inform the .NET Runtime of what processing you wish to be done within that thread.

You do this with the help of a ThreadStart delegate. The function you specify will begin executing once the thread starts. Note that this function that you specify must not take any parameters, and must have a void return type. Let’s try creating a new thread. Create a new project (a Console Application will do just fine), and copy the code shown below:

 

    class Program

    {

        static void Main(string[] args)

        {

            Thread newThread = new Thread(new ThreadStart(OtherFunction));

            newThread.Start();

            Console.WriteLine(“Main thread going off to sleep”);

            Thread.Sleep(1000);

            Console.WriteLine(“Main thread has woken up. Returning”);

        }

        static void OtherFunction()

        {

            for (int i=1; i<=10; i++)

            {

                Console.WriteLine(“Inside the new thread. Current iteration = ” + i);

                Thread.Sleep(100);

            }

        }

    }

You should obtain an output similar to what is shown:

I’ll now explain what the above lines do.

Thread newThread = new Thread(new ThreadStart(OtherFunction)); 

We first create a Thread object named newThread. The constructor takes in a ThreadStart delegate – “OtherFunction”. Once our new thread starts, it will begin executing this function. When this function returns, our new thread will stop executing.

newThread.Start();

Even though we created a new thread in line 1, the thread doesn’t begin executing until we call the Start() method on it.

Thread.Sleep(1000); 

The Thread class exposes a static function called Sleep. This function causes the current thread to sleep (or pause) for a certain amount of time. The above line causes the main thread to sleep for 1000 milliseconds. My main aim in calling this function was to show you that even though the main thread went off to sleep (or was paused) for nearly one second, the other thread we created kept on executing in the background. That’s why I’ve even added Console.WriteLine() statements immediately before the thread went off to sleep, and immediately after it woke up.

The code in OtherFunction() is pretty straightforward. It has a for loop that loops 10 times. Each time it sleeps for 100 milliseconds. Once it comes out of the loop, it returns, effectively terminating the thread. As you can see from the output, even though the main thread was sleeping, this thread was executing in the background.

One thing you’ll notice from the image above, is that the new thread began executing, and had also completed one iteration of the for loop, before the main thread went off to Sleep. The reason being that – when there are multiple threads running within a process, you cannot control which thread should run when, unless you use some sort of synchronization mechanism within the threads. We’ll touch this topic in the next chapter.

One thing before we move on to the next topic – in the OtherFunction code above, change the “10” to “20” (i.e., make the for loop iterate 20 times instead of 10 – effectively making it run for 2 seconds – since in each iteration it sleeps for 1/10th of a second or 100 milliseconds). You’ll find that even though the main thread wakes up after one second, the new thread keeps on running. This is because, the application only exits when all foreground threads have been terminated.

If we had set the new thread to be a background thread, it wouldn’t have prevented the process from terminating. In the code below, we set the new thread to be a background thread. As expected, the process terminates when the first thread wakes up (even though our new thread was supposed to iterate through the for loop 20 times, it iterates only 10 times – because the first thread wakes up by that time and returns – and since it was the only foreground thread, the process terminates):

    class Program

    {

        static void Main(string[] args)

        {

            Thread newThread = new Thread(new ThreadStart(OtherFunction));

            newThread.Start();

            Console.WriteLine(“Main thread going off to sleep”);

            Thread.Sleep(1000);

            Console.WriteLine(“Main thread has woken up. Returning”);

        }

        static void OtherFunction()

        {

            Thread.CurrentThread.IsBackground = true;

            for (int i=1; i<=20; i++)

            {

                Console.WriteLine(“Inside the new thread. Current iteration = “ + i);

                Thread.Sleep(100);

            }

        }

    }

The ParameterizedThreadStart Delegate:

What if you want to pass a parameter to the function which you want to execute within your new thread? In that case, you cannot use the ThreadStart delegate.

You need to use the ParameterizedThreadStart delegate, as shown below:

 

    class Program

    {

        static void Main(string[] args)

        {

            Thread newThread = new Thread(new ParameterizedThreadStart(OtherFunction));

            newThread.Start(“Hello”);

            Console.WriteLine(“Main thread going off to sleep”);

            Thread.Sleep(1000);

            Console.WriteLine(“Main thread has woken up. Returning”); 

        }

        static void OtherFunction(object param)

        {

            Console.WriteLine(“Parameter passed to OtherFunction : “ + param.ToString());

            for (int i = 1; i <= 10; i++)

            {

                Console.WriteLine(“Inside the new thread. Current iteration = “ + i);

                Thread.Sleep(100);

            }

        }

    }

Since the parameter is of type object, you can pretty much pass in anything you want. If you want to pass in multiple parameters, you can encapsulate them within an instance of another class you create, and then pass in that instance to the function, as shown below:

    class Person

    {

        public String Name;

        public int Age;

    }

    class Program

    {

        static void Main(string[] args)

        {

            Thread newThread = new Thread(new ParameterizedThreadStart(OtherFunction));

            Person p = new Person();

            p.Name = “Mustansir”;

            p.Age = 22;

            newThread.Start(p);

         }

        static void OtherFunction(object param)

        {

            Person p = (Person)param;

            Console.WriteLine(“Person information obtained : “ + p.Name);

            Console.WriteLine(“Person’s Age : “ + p.Age);

        }

    }