- 1 Welcome
- 2 Overview
- 3 Start thread
- 4 Pass arguments
- 5 Call method on other class
- 6 More thread methods
Multi-threading in C#
This tutorial will take you through the basics of how to work with threads in C#. The concept is very similar to that of Java-threads.
Multi-threading overview
The threading functionality exists in the namespace System.Threading
This namespace provides classes and interfaces which enable multithreaded programming, i.e. parallel execution of code, and leveraging threads.
Example usage
- Separate heavy calculations from UI (to avoid freezes)
- Regularly query external service, and notify application if new data arrived (polling)
- To avoid stopping processing when waiting for user's input
- When you have independent tasks, which do not intersect
- Handling multiple clients in a client-server setup with sockets
Starting a thread, and printing numbers
In Java the Thread
constructor takes an instance of a class, which implements the interface Runnable
.
In C# the Thread
constructor takes a delegate, i.e. either a lambda expression, or a method reference.
As an example, we would like to execute the following method in a new thread:
public void PrintNumbers()
{
for (int i = 0; i < 1000; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
This method just prints out numbers from 0 to 999. Notice the Thread.Sleep(100)
method call, which sleeps the current thread for 100 milliseconds. Identical to the sleep()
method in Java.
Now, we would like to create a thread to execute this method in a new thread. That can be done as follows:
Thread thread = new Thread(PrintNumbers);
thread.Start();
A new thread instance is created, the constructor takes a method reference to the PrintNumbers
method shown above.
When the Start()
method is called on the thread
a new thread is created, and the method is executed.
Passing arguments
In the previous example, we just referenced a method. This can be done, when we don't need to pass any arguments.
The below method also prints numbers, but requires an argument.
public void PrintNumbers(int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
The way we start the thread now is to use a lambda expression, like below:
Thread thread = new Thread( () => PrintNumbers(1000) );
thread.Start();
This lambda expression is an anonymous method.
() => PrintNumbers(1000)
The leading ()
defines the arguments to be passed to the method. In this case, there are none, so the parameter list is empty.
The =>
is the lambda operator, so the right hand side is the functionality to execute, in this case it's a method call to PrintNumbers
.
Calling a method on another class
Sometimes we would like to keep the behaviour in a separate class. E.g. in Java we usually create a separate class, which implements the Runnable
interface, and so the run()
is called, when the thread is started. We can do something similar in C#.
Below is a class, which has a method to print numbers, like previous examples.
public class NumberPrinterClass
{
public void PrintNumbers(int count)
{
for (int i = 0; i < count; i++)
{
Console.WriteLine(i);
Thread.Sleep(100);
}
}
}
Now, we would like to execute this functionality in a thread, created from a different class.
In the below main method, a new instance of the above class is created, and then a thread, which is started.
static void Main(string[] args)
{
NumberPrinterClass npc = new();
Thread thread = new Thread(() => npc.PrintNumbers(100));
thread.Start();
}
More thread methods
Similar to Java, we have a couple of methods available for the threads. Relevant methods are:
- Thread.sleep(milliseconds : long)
- thread.Join(otherThread) - to tell a thread to not start until the argument thread object is finished. This will make the threads run in serial.
- thread.Interrupt() - to wake up a sleeping thread. It throws an exception, which must be handled.