Threads

The majority of processes seen on operating systems today are single threaded, meaning there is a single path of execution within the process. Should a process have to perform many sub tasks during it's operation then a single threaded process would sequence these tasks in a serial manner, with each sub task being required to wait for the completion of the previous sub task before commencement. Such an arrangement can lead to great inefficiency in the use of the processor and in the apparent responsiveness of the computer.

An example can illustrate the advantages of having multiple threads of execution as shown in the figure. Suppose a user wants to print a document, a user process can be initiated to accept input from the operator to select the print action and start the printing action. Should the user process be required to check for further user commands subsequent to initiating the print there are two options :

(i) the process can stop the printing periodically, poll for user input, then continue printing, or

(ii) wait until printing has completed before accepting user input.

Either of these alternatives slow down printing and/or decrease responsiveness. By contrast a multi-threaded process can have many paths of execution. A multi-threaded application can delegate the print operation to a different thread of execution. The input thread and print thread then run in parallel until printing is completed.

Each thread has access to the allocated resources within the process and can access global variables available to all threads. In a multi-threaded process each thread 'believes' it has independent access to its own 'virtual machine' with the scheduler being responsible for allocation of CPU quanta to threads to optimise throughput efficiency.

Threads within the same task share resources such as file pointers and code segments. Swapping between threads within a process presents a much smaller overhead to the scheduler than swapping between processes. This is because less context related data must be saved to enable successful restoration of that context later. For this reason threads are often known as 'light weight processes' (LWPs) with normal processes being correspondingly known as heavyweight processes. Typically, when a thread context switch is performed, only the program counter and register set need to be saved in the PCB. Heavy-weight processes typically don?t share such resources so when heavy-weight processes context switch, all this additional info must be saved.

Although threads have many advantages as described above, they also have disadvantages, one of these being that any single 'rogue' thread within the process can cause the whole process to fail. Programming threads is also more complex than for simple processes as kernel code and libraries must have 100% re-entrant code. Special care must be taken to ensure that pre-emption cannot occur within critical sections of code within which inconsistencies could occur should another thread gain access at the wrong time. Other such problem is "what happens if a thread forks another process ?", it must be defined how threads within a process are affected in this case.

Linux

Windows NT

There are two types of threads: user-space and kernel-space.

User space threads consist of internal cooperative multitasking switches between sub tasks defined with a process.

A thread may send a signal, perform it?s own switch or be invoked by a timer to give up the thread of execution. The user stack is then manipulated to save the thread context Switching is typically faster for user threads than kernel threads.

User threads have disadvantages in that starvation can occur if one thread does not give up the CPU. Also should a thread become blocked waiting on a resource, all other threads will be blocked as well. User threads cannot take advantage of SMP systems should such a multi processor environment be available.

Similarly to its implementation of processes, Windows NT threads are implemented as Objects.

Certain attributes of a thread may restrict or qualify the attributes applicable to the overall process.

The thread has a context attribute which allows the operating system to correctly perform context switching as required.

The Windows NT Posix subsystem does not support multi-threading, though the OS/2 and Win 32 subsystems do.

All threads are subject to manipulation by the kernel, which will schedule their priority for access to the CPU. The kernel is concerned with its own view of a thread called a kernel thread object. The kernel does not use thread handles but instead accesses threads directly from it's kernel process object.

Windows NT threads support SMP, with individual threads (and processes for that matter) having a defined processor affinity which can define on which of a selection of available processors the thread may be run.

Kernel-space threads may be implemented in the kernel by allocation of a thread table to a process. The kernel schedules threads within the time quantum allocated to the process.

This method requires slightly more overhead for context switching but advantages include true pre-emption of tasks, thus overcoming the starvation problem. I/O blocking is also no longer a problem. Threads can automatically take advantage of SMPs with run time efficiency improving linearly as CPUs are added.