Light-weight process

In computer operating systems, a light-weight process (LWP) is a means of achieving multitasking. In the traditional meaning of the term, as used in Unix System V and Solaris, a LWP runs in user space on top of a single kernel thread and shares its address space and system resources with other LWPs within the same process. Multiple user-level threads, managed by a thread library, can be placed on top of one or many LWPs - allowing multitasking to be done at the user level, which can have some performance benefits.[1]

In some operating systems, there is no separate LWP layer between kernel threads and user threads. This means that user threads are implemented directly on top of kernel threads. In those contexts, the term "light-weight process" typically refers to kernel threads and the term "threads" can refer to user threads.[2] On Linux, user threads are implemented by allowing certain processes to share resources, which sometimes leads to these processes to be called "light weight processes".[3][4] Similarly, in SunOS version 4 onwards (prior to Solaris) "light weight process" referred to user threads.[1]

Kernel threads

Kernel threads are handled entirely by the kernel. They need not be associated with a process; a kernel can create them whenever it needs to perform a particular task. Kernel threads cannot execute in user mode. LWPs (in systems where they are a separate layer) bind to kernel threads and provide a user-level context. This includes a link to the shared resources of the process to which the LWP belongs. When a LWP is suspended, it needs to store its user-level registers until it resumes, and the underlying kernel thread must also store its own kernel-level registers.

Performance

LWPs are slower and more expensive to create than user threads. Whenever an LWP is created a system call must first be made to create a corresponding kernel thread, causing a switch to kernel mode. These mode switches would typically involve copying parameters between kernel and user space, also the kernel may need to have extra steps to verify the parameters to check for invalid behavior. A context switch between LWPs means that the LWP that is being pre-empted has to save its registers, then go into kernel mode for the kernel thread to save its registers, and the LWP that is being scheduled must restore the kernel and user registers separately also.[1]

For this reason, some user level thread libraries allow multiple user threads to be implemented on top of LWPs. User threads can be created, destroyed, synchronized and switched between entirely in user space without system calls and switches into kernel mode. This provides a significant performance improvement in thread creation time and context switches.[1] However, there are difficulties in implementing a user level thread scheduler that works well together with the kernel.

Scheduler activation

While the user threading library will schedule user threads, the kernel will schedule the underlying LWPs. Without coordination between the kernel and the thread library the kernel can make sub-optimal scheduling decisions. Further, it is possible for cases of deadlock to occur when user threads distributed over several LWPs try to acquire the same resources that are used by another user thread that is not currently running.[1]

One solution to this problem is scheduler activation. This is a method for the kernel and the thread library to cooperate. The kernel notifies the thread library's scheduler about certain events (such as when a thread is about to block) and the thread library can make a decision on what action to take. The notification call from the kernel is called an "upcall".

A user level library has no control over the underlying mechanism, it only receives notifications from the kernel and schedules user threads onto available LWPs, not processors. The kernel's scheduler then decides how to schedule the LWPs onto the processors. This means that LWPs can be seen by the thread library as "virtual processors".[5]

Supporting operating systems

Solaris has implemented a separate LWP layer since version 2.2. Prior to version 9, Solaris allowed a many-to-many mapping between LWPs and user threads. However, this was retired due to the complexities it introduced and performance improvements to the kernel scheduler.[1][6]

UNIX System V and its modern derivatives IRIX, SCO OpenServer, HP-UX and IBM AIX allow a many-to-many mapping between user threads and LWPs.[5][7]

NetBSD 5.0 introduced a new, scalable 1:1 threading model. Each user thread (pthread) has a kernel thread called a light-weight process (LWP). Inside the kernel, both processes and threads are implemented as LWPs, and are served the same by the scheduler.[8]

Implementations

See also

References

  1. ^ a b c d e f Vahalia, Uresh (1996). "Threads and Lightweight Processes". UNIX Internals - The New Frontiers. Prentice-Hall Inc. ISBN 0-13-101908-2.
  2. ^ "IBM AIX Compilers". IBM. 2004. Archived from the original on 2012-07-14. Retrieved 24 Jan 2010. On AIX, the term lightweight process usually refers to a kernel thread.
  3. ^ Bovet, Daniel P.; Cesati, Marco (2005). "3.1. Processes, Lightweight Processes, and Threads". Understanding the Linux Kernel (3rd ed.). O'Reilly Media.
  4. ^ Walton, Sean (1996). "Linux Threads Frequently Asked Questions (FAQ)". Retrieved 24 Jan 2010.
  5. ^ a b Silberschatz; Galvin; Gagne (2004). "Chapter 5 - Threads". Operating System Concepts with Java (Sixth ed.). John Wiley & Sons, Inc.
  6. ^ "Multithreading in the SolarisTM Operating Environment" (PDF). Sun Microsystems. 2002. Retrieved 24 Jan 2010.
  7. ^ "IBM AIX 6.1 - Thread tuning". IBM. 2009. Retrieved 24 Jan 2010.
  8. ^ "Thread scheduling and related interfaces in NetBSD 5.0" (PDF). The NetBSD Project. 2009. Retrieved 20 Dec 2022.