Understanding Multithreading in C#: Five Implementation Approaches
- What is a Thread?
A process serves as the fundamental unit of program execution in an operating system, holding resources for applications. Processes contain threads, and process resources are shared among threads. However, threads themselves do not own resources independently.
- Foreground Threads vs Background Threads
When a program closes, background threads terminate immediately, while foreground threads continue executing until completion. Threads created through the Thread class default to foreground threads. All other threading approaches create background threads by default.
Multithreading Implementation Approaches
1. Asynchronous Multithreading with BeginInvoke
for(int idx = 0; idx < 5; idx++)
{
Action<string> asyncAction = param =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: {0}, Thread ID: {1}",
param, Thread.CurrentThread.ManagedThreadId);
};
asyncAction.BeginInvoke("Value" + idx, null, null);
}
Console.WriteLine("----------Main program ended, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
<div></div></div>### 2. Using the Thread Class
<div><div></div>```
static void Main(string[] args)
{
Console.WriteLine("----------Main program started, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
for(int idx = 0; idx < 5; idx++)
{
ParameterizedThreadStart threadDelegate = payload =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: {0}, Thread ID: {1}",
payload, Thread.CurrentThread.ManagedThreadId);
};
Thread workerThread = new Thread(threadDelegate);
workerThread.Start(idx);
}
Console.WriteLine("----------Main program ended, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
for(int idx = 0; idx < 5; idx++)
{
WaitCallback poolCallback = stateObj =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: {0}, Thread ID: {1}",
stateObj, Thread.CurrentThread.ManagedThreadId);
};
ThreadPool.QueueUserWorkItem(poolCallback, idx);
}
Console.WriteLine("----------Main program ended, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
<div></div></div>### 4. Task Parallel Library
<div><div></div>```
static void Main(string[] args)
{
Console.WriteLine("----------Main program started, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
TaskFactory taskManager = new TaskFactory();
for(int idx = 0; idx < 5; idx++)
{
Action<object> workAction = stateObj =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: {0}, Thread ID: {1}",
stateObj, Thread.CurrentThread.ManagedThreadId);
};
taskManager.StartNew(workAction, idx);
}
Console.WriteLine("----------Main program ended, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
Action workUnit1 = () =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: 1, Thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
};
Action workUnit2 = () =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: 2, Thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
};
Action workUnit3 = () =>
{
for(int counter = 0; counter < 1000000000; counter++)
{ }
Console.WriteLine("Parameter: 3, Thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
};
Parallel.Invoke(workUnit1, workUnit2, workUnit3);
Console.WriteLine("----------Main program ended, Thread ID: {0}----------",
Thread.CurrentThread.ManagedThreadId);
Console.Read();
}
<div></div></div>These five examples demonstrate different approaches to implementing multithreading in C#. Each method has its own use cases and characteristics, ranging from low-level thread management to higher-level abstractions provided by the Task Parallel Library.