C Sharp

Threads and Multitasking

A thread is a unit of processing, and multitasking is the simultaneous execution of multiple threads. Multitasking comes in two flavors: cooperative and preemptive. Very early versions of Microsoft Windows supported cooperative multitasking, which meant that each thread was responsible for relinquishing control to the processor so that it could process other threads. For those of us with backgrounds in other operating systems-in my case, IBM System/38 (CPF) and OS/2-each of us has our own story of the day we hung the computer because we didn't place a call to PeekMessage in our code to allow other threads in the system to be served by the CPU. "I have to do what?!" was our typical response.

However, Microsoft Windows NT-and, later, Windows 95, Windows 98, and Windows 2000-support the same preemptive multitasking that OS/2 does. With preemptive multitasking, the processor is responsible for giving each thread a certain amount of time in which to execute-a timeslice. The processor then switches among the different threads, giving each its timeslice, and the programmer doesn't have to worry about how and when to relinquish control so that other threads can run. Because .NET will only work only on preemptive multitasking operating systems, this is what I'll be focusing on.

By the way, even with preemptive multitasking, if you're running on a single processor machine, you don't really have multiple threads executing at the same time. Because the processor is switching between processes at intervals that number in the milliseconds, it just "feels" that way. If you want to run true multiple threads concurrently, you'll need to develop and run your code on a machine with multiple processors.

Context Switching

Context switching is integral to threading and a difficult concept for some, so let me give a brief overview here in the "Threading Basics" section.

The processor uses a hardware timer to determine when a timeslice has ended for a given thread. When the hardware timer signals the interrupt, the processor saves all registers for the current thread onto the stack. Then the processor moves those same registers from the stack into a data structure called a CONTEXT structure. When the processor wants to switch back to a previously executing thread, it reverses this procedure and restores the registers from the CONTEXT structure associated with the thread. This entire procedure is called context switching.