Multi-Threading Interview Questions and Answers in C#

Multi-Threading Interview Questions and Answers in C#

In this article, I am going to discuss the most frequently asked Multi-Threading Interview Questions and Answers in C#. Please read our previous article where we discussed the most frequently asked Nested Types Interview Questions in C# with Answers. As part of this article, we are going to discuss the following Multi-Threading Interview Questions and Answers in C#.

  1. What are the Thread and Process?
  2. What is the difference between Process and Thread?
  3. Why we need Multi-threading in our project?
  4. What are the advantages and disadvantages of multithreading in C#?
  5. How can we create a Thread in C#?
  6. Why does a delegate need to be passed as a parameter to the Thread class constructor?
  7. How to pass the parameter in Thread?
  8. Why we need a ParameterizedThreadStart delegate?
  9. When to use ParameterizedThreadStart over ThreadStart delegate?
  10. How to pass data to the thread function in a type-safe manner?
  11. How to retrieve the data from a thread function?
  12. What is the difference between Threads and Tasks?
What are the Thread and Process?

Process – Process is something that the operating system uses to execute a program by providing the resources required. Each process has a unique process id associated with it. We can view the process within which a program is running using the windows task manager.

Thread – A Thread is a lightweight process that is responsible for executing application code. A process has at least one thread which is commonly called the main thread which actually executes the application code. A single process can have multiple threads.

Every application by default contains one thread to execute the program and that thread is known as the main thread. So every program by default is a single-threaded model.

What is the difference between Process and Thread?

A process is started when you start an Application. The process is a collection of resources like virtual address space, code, security contexts, etc. A process can start multiple threads. Every process starts with a single thread called primary thread. You can create n number of threads in a process. Threads share the resources allocated to the process. A process is the parent and threads are his children.

Why we need Multi-threading in our project?

This is one of the most frequently asked Multi-Threading Interview Questions in C#.NET. Let us discuss this question

Multi-threading is used to run multiple threads simultaneously. Some main advantages are:

  1. You can do multiple tasks simultaneously. For e.g. saving the details of the user to a file while at the same time retrieving something from a web service.
  2. Threads are much lightweight than process. They don’t get their own resources. They used the resources allocated to a process.
  3. Context-switch between threads takes less time than process.
What are the advantages and disadvantages of multithreading?

I think this Multi-Threading Interview Question is the most asked interview question in the dot net. So let us discuss the advantages and disadvantages

Advantages of multithreading:

  1. To maintain a responsive user interface
  2. It makes the efficient use of processor time while waiting for I/O operations to complete.
  3. To split large, CPU-bound tasks to be processed simultaneously on a machine that has multiple CPUs/cores. 

Disadvantages of multithreading:

  1. On a single-core/processor machine threading can affect performance negatively as there is overhead involved with context-switching.
  2. Have to write more lines of code to accomplish the same task.
  3. Multithreaded applications are difficult to write, understand, debug and maintain.

Please Note: Only use multithreading when the advantages of doing so outweigh the disadvantages.

How can we create a Thread in C#?

To create a THREAD, we need to create an instance of Thread class (Thread class provided by System.Threading namespace) and to its constructor, we have to pass the function name as a parameter that we want the thread to execute. Then we need to call the start method of the Thread class. 

Let us understand this with an example as shown below.

Multi-Threading Interview Questions and Answers in C#

In the above example, the following statement does the same
Thread T1 = new Thread(Number.PrintNumbers); T1.Start();

We can rewrite the above line using the ThreadStart delegate as shown below.
Thread T1 = new Thread(new ThreadStart(Number.PrintNumbers));
T1.Start();

Why does a delegate need to be passed as a parameter to the Thread class constructor?

As we know the purpose of creating a Thread is to execute a function. We also know that a delegate is a type-safe function pointer meaning it points to a function that the thread has to execute. In short, all threads require an entry point to start execution. Any thread that we create will need an explicitly defined entry point i.e. a pointer to the function from where they should begin execution. So threads always require a delegate.

In the code below, we are not explicitly creating the ThreadStart delegate, then how is it working here?

Thread T1 = new Thread(Number.PrintNumbers);

It’s working in spite of not creating the ThreadStart delegate explicitly because the framework is doing it automatically for us. We can also rewrite the same line using delegate() keyword as shown below.
Thread T1 = new Thread(delegate() { Number.PrintNumbers(); });

We can also rewrite the same line using the lambda expression as shown below.
Thread T1 = new Thread(() => Number.PrintNumbers());

How to pass the parameter in Thread?

In the constructor of Thread, we can pass the method name which accepts only a single parameter. Then we have to pass the parameter into the Start method.

Why we need a ParameterizedThreadStart delegate?

When we need to pass data to the thread function then in such situations we need to use ParameterizedThreadStart delegate. Here is an example that shows the usage of a ParameterizedThreadStart delegate.

namespace MultithreadingDemo
{
    class Program
    {
        public static void Main()
        {
            Console.WriteLine("Please enter the target number");
            object target = Console.ReadLine();

            // Create an instance of ParameterizedThreadStart delegate
            ParameterizedThreadStart parameterizedThreadStart =
                new ParameterizedThreadStart(Number.PrintNumbers);
            Thread T1 = new Thread(parameterizedThreadStart);
            // Pass the traget number to the start function, which
            // will then be passed automatically to PrintNumbers() function
            T1.Start(target);
        }
    }
    class Number
    {
        public static void PrintNumbers(object target)
        {
            int number = 0;
            if (int.TryParse(target.ToString(), out number))
            {
                for (int i = 1; i <= number; i++)
                {
                    Console.WriteLine(i);
                }
            }
        }
    }
}

The code in the Main() function can also be written as shown below.

public static void Main()
{
    Console.WriteLine("Please enter the target number");
    object target = Console.ReadLine();
    Thread T1 = new Thread(Number.PrintNumbers);
    T1.Start(target);
}

In the above example, we are not explicitly creating an instance of the ParameterizedThreadStart delegate. Then how is it working?

It’s working because the compiler implicitly converts new Thread(Number.PrintNumbers)  to

new Thread(new ParameterizedThreadStart(Number.PrintNumbers));
When to use ParameterizedThreadStart over ThreadStart delegate?

We need to use ParameterizedThreadStart delegate if we have some data to pass to the Thread function, otherwise, just use ThreadStart delegate.

Please note: Using ParameterizedThreadStart delegate and Thread.Start(Object) method to pass data to the Thread function is not type-safe as they operate on object datatype and any type of data can be passed. In the above, If we try to change the data type of the target parameter of PrintNumbers() function from object to int, a compiler error will be raised as the signature of PrintNumbers() function does not match with the signature of ParameterizedThreadStart delegate.

How to pass data to the thread function in a type-safe manner?

This Multi-Threading Interview Questions can be asked in almost all interviews. To pass data to the Thread function in a type-safe manner, encapsulate the thread function and the data it needs in a helper class and use the ThreadStart delegate to execute the thread function. An example is shown below.

namespace ThreadingExample
{
    class Program
    {
        public static void Main()
        {
            // Prompt the user for the target number
            Console.WriteLine("Please enter the target number");
            // Read from the console and store it in target variable
            int target = Convert.ToInt32(Console.ReadLine());

            // Create an instance of the Number class, passing it
            // the target number that was read from the console
            Number number = new Number(target);
            // Specify the Thread function
            Thread T1 = new Thread(new ThreadStart(number.PrintNumbers));
            // Alternatively we can just use Thread class constructor as shown below
            // Thread T1 = new Thread(number.PrintNumbers);
            T1.Start();
        }
    }

    // Number class also contains the data it needs to print the numbers
    class Number
    {
        int _target;
        // When an instance is created, the target number needs to be specified
        public Number(int target)
        {
            // The targer number is then stored in the class private variable _target
            this._target = target;
        }

        // Function prints the numbers from 1 to the traget number that the user provided
        public void PrintNumbers()
        {
            for (int i = 1; i <= _target; i++)
            {
                Console.WriteLine(i);
            }
        }
    }
}
How to retrieve the data from a thread function?

Retrieving data from Thread function using the callback method.

namespace ThreadStartDelegateExample
{
    // Step 1: Create a callback delegate. The actual callback method
    // signature should match with the signature of this delegate.
    public delegate void SumOfNumbersCallback(int sumOfNumbers);

    // Step 2: Create Number class to compute the sum of numbers and
    // to call the callback method
    class Number
    {
        // The traget number this class needs to compute the sum of numbers
        int _target;

        // Delegate to call when the the Thread function completes                 
        // computing the sum of numbers
        SumOfNumbersCallback _callbackMethod;

        // Constructor to initialize the target number and the callback delegateinitialize
        public Number(int target, SumOfNumbersCallback callbackMethod)
        {
            this._target = target;
            this._callbackMethod = callbackMethod;
        }

        // This thread function computes the sum of numbers and then invokes
        // the callback method passing it the sum of numbers
        public void ComputeSumOfNumbers()
        {
            int sum = 0;
            for (int i = 1; i <= _target; i++)
            {
                sum = sum + i;
            }

            if (_callbackMethod != null)
            {
                _callbackMethod(sum);
            }
        }
    }

    // Step 3: This class consumes the Number class created in Step 2
    class Program
    {
        // Callback method that will receive the sum of numbers
        public static void PrintSumOfNumbers(int sum)
        {
            Console.WriteLine("Sum of numbers is " + sum);
        }
        public static void Main()
        {
            // Prompt the user for the target number
            Console.WriteLine("Please enter the target number");
            // Read from the console and store it in target variable
            int target = Convert.ToInt32(Console.ReadLine());

            // Create an instance of callback delegate and to it's constructor
            // pass the name of the callback function (PrintSumOfNumbers)
            SumOfNumbersCallback callbackMethod = newSumOfNumbersCallback(PrintSumOfNumbers);

            // Create an instance of Number class and to it's constrcutor pass the target
            // number and the instance of callback delegate
            Number number = new Number(target, callbackMethod);

            // Create an instance of Thread class and specify the Thread function to invoke
            Thread T1 = new Thread(new ThreadStart(number.ComputeSumOfNumbers));
            T1.Start();
        }
    }
}
What is the difference between Threads and Tasks?
  1. Tasks are the wrapper around Thread and ThreadPool classes. Below are some major differences between Threads and Tasks:
  2. A Task can return a result but there is no proper way to return a result from Thread.
  3. We can apply chaining to multiple tasks but we cannot in threads.
  4. We can wait for Tasks without using Signalling. But in Threads, we have to use event signals like AutoResetEvent and ManualResetEvent.
  5. We can apply the Parent/Child relationship in Tasks. A Task at one time becomes a parent of multiple tasks. Parent Task does not complete until it’s child tasks are completed. We do not have any such mechanism in the Thread class.
  6. Child Tasks can propagate their exceptions to the parent Task and All child exceptions are available in the AggregateException class.
  7. Task has an in-build cancellation mechanism using the CancellationToken class.

In the next article, I am going to discuss the most frequently asked Deadlock Interview Questions and Answers in C#. In this article, I try to explain most frequently asked Multi-Threading Interview Questions and Answers in C#. I hope this article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *