hile a "process" is the way that operating systems compartmentalize running applications from each other, a "thread" is a path of execution—the basic unit to which an operating system allocates processor time. A single process comprises one or multiple threads.
Preemptive multitasking operating systems such as Windows store all threads in a thread queue, and execute them by allocating a processor time slice to each thread consecutively. The OS suspends the currently executing thread when its time slice elapses, and resumes running another thread. As the system switches from one thread to another, it saves the thread context
(all the information the thread needs to resume execution) of the preempted thread, and reloads the saved thread context of the next thread in the thread queue. Because each time slice is small, it appears to users as if multiple threads are executing simultaneously, even if there is only one processor.
Multiprocessor or multi-core systems achieve threading via multiprocessing, wherein different threads and processes can run literally simultaneously on different processors or cores.
Thread switching is always considered cheaper than process switching on Windows OSs.
The Microsoft .NET runtime divides OS processes into managed sub-processes called Application Domains (see the System.AppDomain namespace documentation for details). Each managed process can have one or many application domains. Similarly, each managed process can have multiple managed threads. Managed threads can move freely across application domains within the same managed process.
Foreground and Background Threads
A managed thread can either be a foreground or background thread. The only difference is that a background thread does not keep the managed parent process running. When all foreground threads complete, the OS shuts the process down regardless of whether any background threads belonging to that process are still running. It stops all background threads at the point of process shutdown.
Advantages/Use of Multithreading Apps
The main advantages of using multithreading are as follows:
- Doing multiple tasks in parallel to save time and utilize CPU to the maximum.
- Doing tasks/calculations in the background so that application can still respond to user's action while doing calculations.
The main challenges faced while developing multithreading applications are:
Thread Local Storage
- Managing synchronization if threads access common resources.
- Managing deadlocks and context switches when there are too many threads, because context switches consume resources.
- Scheduling of threads to avoid unexpected results at runtime.
Thread Local Storage (TLS) is the method by which each thread is able to store thread-specific data in the memory. Threads need to store two main types of data: Runtime/Dynamically bound
and Load time/statically bound
The .NET framework also provides two ways to use managed TLS:
- Thread-relative static fields specified at compile time. These provide the best performance.
- Data slots for runtime/dynamically bound fields. Data is stored as type Object, so casting is required. This type has slower performance than static fields.
Managed TLS is unique to a thread and application domain. Two important points to note here are:
- A thread needs to maintain an independent copy of its data in each application domain in which it operates.
- Within an application domain, a thread cannot modify another thread's data even if both threads are using the same memory locations.