This post will contain my notes on the C# System.Threading namespace. For an extremely basic introduction to Threads, see my previous post [LINK]
Thread Class
The Thread Class is a found in the System.Threading namespace and can be used to create new Threads, get their status and manage their priorities.
The following is an example of how to use the Thread class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Threading; namespace ThreadingExample { public static class ThreadingExample { public static void SomeThreadedMethod() { Console.WriteLine("Hello, world!"); Thread.Sleep(0); // tell Windows that we're done } public static void Main() { Thread t = new Thread(new ThreadStart(SomeThreadedMethod)); t.Start(); t.Join(); } } } |
This is probably not the most useful example of how to use a Thread, but it’s an example.
We create a Thread (called t), and give it a method to run (SomeThreadedMethod). Then we tell the t to start processing, then we tell Main() to wait until t has finished before moving on.
We use the Thread.Sleep method in SomeThreadedMethod to tell Windows that the thread that it is running in has finished. Without this, the thread would continue to run until the Windows scheduler has closed it’s time slot.
Thread Types
There are two types of Threads:
- Foreground Thread
- Background Thread
A foreground thread is used to keep an application going, its the thread that powers the GUI for an application. Google Chrome’s browser window is an example of a Foreground thread.
A background thread is meant for processing data without locking up the foreground thread.
Again, another gross over simplification coming
Imagine that you’re downloading a file with Google Chrome. There are (among other foreground and background threads) two Threads in use here:
- 1 Foreground thread keeping Chrome’s browser window responsive (opening new tabs, scrolling up and down, etc.)
- 1 Background thread performing the download action
The file download is performed on a background thread, because we don’t want Chrome to become unresponsive while downloading the file.
In .NET and C#, as soon as all Foreground threads are finished, the application that spawned them will close.
Technically is the CLR (Common Language Runtime) that closes the application
Passing Data
To pass data to a thread, we do the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
using System; using System.Threading; namespace ThreadingExample { public static class ThreadingExample { public static void SomeThreadedMethod(object o) { Console.WriteLine((string)o); Thread.Sleep(0); // tell Windows that we're done } public static void Main() { Thread t = new Thread(new ParameterizedThreadStart(SomeThreadedMethod)); t.Start("Hello thread!"); t.Join(); } } } |
This extremely simple example created a new thread using the ParameterizedThreadStart option which tells the Thread that we want to pass it some data when we start it. Then we do just that, we pass it a string to output to the Console when we start the thread.
A short note on the Console:
The console uses synchronisation to allow us to output to it from different threads.
If we wanted to output from the Main thread whilst t was running, then the Console would wait for t to finish writing to it before allowing Main to write to it.
Stopping Threads
The best way to stop a thread (without causing a ThreadAbortException) is to use a shared variable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Threading; namespace ThreadingExample { public static class ThreadingExample { public static void Main() { bool continueProcessing = true; Thread t = new Thread(new ThreadStart(() => { while(continueProcessing){ Console.WriteLine("Hello Thread!"); Thread.Sleep(1000); } })); t.Start(); Console.WriteLine("To exit, press any key"); Console.ReadLine(); continueProcessing = false; t.Join(); } } } |
Threads have their own call stack, featuring the values of all local variables and any methods called during the processing of that Thread.
If you need to have multiple threads in an application then hand rolling them isn’t that great a solution. This is because you need to know, ahead of time, just how many threads you’ll need. This isn’t always possible, so to get around this, we use the ThreadPool class.
More on that next time.