Threads, Light Weight Processes, and all that.

Since context switching is relatively expensive, involving several tasks, among them:

A context switch will occur when a process completes or (in a system without user-level threads) when a process makes a blocking system call. An OS call is usually blocking if significant time is required to complete the call, such as an I/O request. In this case, the user task is blocked until the call completes.

Newer operating systems support the idea of user-level threads, light-weight processes, tasks, and kernel-level threads. The idea is to provide more flexibility and less overhead than context switches.

For example, with user threads, no accounting, memory protection since user does not change. Allows user process to keep executing even when it makes a blocking system call.

Each user task can have several user-level threads and several LWP (light weight processes). The light LWPs are scheduled as discussed; each LWP will have exactly one thread active at any time. The task can switch the thread asociated with a process as desired. If a task has several LWPs, it is possible for it to have several I/O transfers occurring in parallel; each will result in that LWP being blocked, but it can significantly reduce the time for the process to complete since all I/O need not be serial.

All threads from the same owner share identical address space and each can corrupt the behavior of the other; its left to the programmer manage these issues. In Solaris, a library is provided for the user to manage threads; these calls do not involve the kernel. They avoid most of the overhead of context swithches.

Each LWP is associated with one kernel thread. A particular kernel thread can be pinned to a particular CPU so that unpinned threads are multiplexed among available unpinned CPUs, but the pinned thread is the only one which may use its pinned CPU.

It is possible to allow user-level threads without providing OS threads. This is what an earlier release of Solaris did as short cut. But then much of the advantage of threading is lost.

Communication Among Processes

The producer/consumer problems illustrated the use of cooperating processes. If this type of code is to be supported by the OS, and multiple processes are used, then mechanisms for efficient interprocess communication must be provided.

A common mechanism for interprocess communication (spurred on by the use of networked systems as well as the use of object-oriented code) is the use of messages. The OS then provides calls such as:

     send( P, message);      Send process P the message.
     receive( Q, message );  Receive a message from process Q, or something
                             similar.
or
     send( A, message );     Place a message in mailbox A.
     receive( A, message );  Retrieve a message from mailbox A.
Usually, the OS will make some gurantees, for example about the ordering of message. (If messages can be sent using Ethernet, messages can get out of order or get lost.)

OS must deal with lost messages and with buffering of messages. For example, the buffering may be of size 0, in which case the sender is blocked until the receiver picks up the message (this is also call a rendezvous), support a buffer of size n, so that the sender is only blocked when the buffer is full, or support infinite buffers so that the sender is always blocked.

The OS may allow the receiver to only receive messages from a particular process, any process, or from any of a group of processes.

Example:

Mach, one of the first distributed OSs, was developed at CMU supports messages through mailboxes, which are called ports in Mach. All kernel calls are made by messages.

The OS msg_send call places a message in a mailbox; the msg_receive is used to receive messages. Port_allocate creates a new mailbox. The user can specify how many messages can be held in the mailbox; the default is eight. The OS guarentees that multiple messages sent from one process to another will be received in order (FIFO), but messages sent from several processes to single mailbox may be out of time order.

Messages consist of a fixed length header and a variable length data portion. The header gives the length of the data and the address of both the receiver and the sender (a return address). The data portion is a list of typed data items. The types are important since OS-defined objects such as read or write access to files can be sent. When a thread sends a message to a full mailbox, it can:

  1. wait until there is room,
  2. wait at most n milliseconds,
  3. not wait at all,
  4. cache exactly one message.

This last sounds strange but is important since several OS threads need to notify a user thread that something has completed and this trick will not block that thread even when a thread's box is full.

Programmer Comms Methods:

  1. Pipes
  2. Shared Variables
  3. GUI Events
  4. Sockets
  5. Streams

System Comms Methods:

  1. Files
  2. Shared Memory
  3. Network Messages


Index Previous Next

Copyright ©2017, G. Hill Price
Send comments to G. Hill Price