.NET Threading Fundamentals
Managed threads in .NET provide execution units within processes. By default, applications run on a single primary thread, but developers can create additional threads for parallel execution using the System.Threading namespace.
Threads and Processes
A process encapsulates an application's execution environment. Threads represent individual execution units within a process. Multithreading becomes beneficial when:
- Applications compete for limited system resources
- User interfaces need to remain responsive during long operatinos
- Parallel execution can reduce task completion time
Background Threads
Background threads don't prevent process termination. New threads default to foreground status. To create a background thread:
var worker = new Thread(() => {
while (true) {
Console.WriteLine($"Network status: {NetworkInterface.GetIsNetworkAvailable()}");
Thread.Sleep(100);
}
});
worker.IsBackground = true;
worker.Start();
Managed Thread Characteristics
Managed threads are implemented through the Thread class with properties including:
ManagedThreadId: Unique thread identifierThreadState: Current execution state (Running, Background, etc.)IsAlive: Indicates active thread status
Thread Lifecycle Management
Creating Threads
Thread constructors support different initialization approaches:
var counterThread = new Thread((object data) => {
if (int.TryParse(data.ToString(), out int max)) {
for (int i = 0; i < max; i++) {
Console.WriteLine($"Iteration: {i}");
Thread.Sleep(50);
}
}
});
counterThread.Start(5);
Pausing Execution
Use Thread.Sleep to suspend thread execution:
Thread.Sleep(250); // Pause for 250ms
Thread.Sleep(Timeout.Infinite); // Suspend indefinitely
Terminating Threads
Modern .NET versions discourage forceful termination. Instead, use cooperative cacnellation patterns:
var cts = new CancellationTokenSource();
var worker = new Thread(() => {
while (!cts.Token.IsCancellationRequested) {
// Perform work
}
});
worker.Start();
cts.Cancel(); // Request termination
Thread Synchronization Techniques
Monitor-Based Synchronization
Use Monitor to protect critical sections:
Monitor.Enter(syncObject);
try {
// Critical section
} finally {
Monitor.Exit(syncObject);
}
Manual Synchronization Primitives
Mutex provides cross-process synchronization:
using (var mtx = new Mutex()) {
mtx.WaitOne();
// Protected operations
mtx.ReleaseMutex();
}
Reader-Writer Locks
ReaderWriterLockSlim optimizes read-heavy scenarios:
public class ResourceManager {
private readonly ReaderWriterLockSlim _lock = new();
public string ReadResource() {
_lock.EnterReadLock();
try {
return _resource;
} finally {
_lock.ExitReadLock();
}
}
public void UpdateResource(string value) {
_lock.EnterWriteLock();
try {
_resource = value;
} finally {
_lock.ExitWriteLock();
}
}
}
Thread Scheduling and Cancellation
Priority Management
Thread priority influences execution order:
var highPriority = new Thread(WorkMethod) {
Priority = ThreadPriority.Highest
};
var lowPriority = new Thread(WorkMethod) {
Priority = ThreadPriority.Lowest
};
Cancellation Patterns
Implement cancellation using CancellationToken:
public void ProcessData(CancellationToken ct) {
while (!ct.IsCancellationRequested) {
// Process data chunks
}
// Cleanup after cancellation
}