This article tries to explain the conceptual aspect of multithreading programming. Much of the explanation is in context with Windows NT. Most of the material is derived from MSDN.
What Are Threads?
Windows NT's basic unit of execution is a thread. That means WIN NT does not execute processes; instead, it executes threads. Threads are code sequences that run multitasked on individual stacks. A thread has its own sequence of code, which gets executed in a concurrent fashion. So threads help us achieve concurrent processing. WIN NT Scheduler controls the execution of all the threads running in a system. In WIN NT, each thread has its own priority, numbered from 0 to 31, based on which WIN NT schedules the execution of each thread. The higher the priority number, the higher the thread's priority. A process may have a single thread or multiple threads. A single process has to have a minimum of one thread. Processes can spawn threads and can terminate threads. A thread can be in one of the three states at given time, such as:
- Running The thread is currently running on one of the CPUs.
- Waiting The thread is in a suspended state and cannot run until a specified event occurs.
- Ready A thread is ready to run, but no processor is currently available.
When a CPU becomes available, the OS finds the highest priority queue with ready threads on it, removes the thread at the head of the queue, and runs it. This process is called a context switch. Each context switch adds a little overhead; as a result, the system will get sluggish as the number of threads increases. WIN NT is a pre-emptive multitasking system; this means that the amount of time for which a thread keeps running is decided by OS and not by the thread itself. If enough CPU time is available and no other higher priority threads are ready, the OS allows the running thread to complete its quota of time, which is called thread quantum. After a thread completes its thread quantum, the OS finds the ready thread at the head of highest priority queue and runs it. If a thread completes its thread quantum and a higher priority thread is ready, the OS pre-empts the currently running thread and runs the higher priority thread.
There are several reasons we may need to use multithreading; the most important of them is to enhance your application's performance. For example, any application that has something to do in the background, irrespective of what is going on in the foreground (User interface); in such applications, there can be one worker thread, which performs a background job; and the main thread, which performs activities related to user interface.
Sometimes multithreaded application designs are more logical and less complex than the same without multithreading. An application which controls temperature receives temperature measurements from two pyrometers (temperature measuring devices) at regular intervals; the application should respond to these measurements in definite time (real time). It is more logical to have to have two threads running which accept temperature measurements from each pyrometer and send the response back.
So it is an important design criterion to have multiple threads or to go for a single threaded application. There is not a hard and fast rule available.
Where Are We Going?
In a multithreaded application, if the threads are independent of each other, it's much easier to design, develop, and debug such applications. But in the practical world, the picture is not so rosy. The threads are always dependent on each other and they share common resources. There starts the world of thread synchronization. In our next session we cover the concepts of thread synchronization.