#LyX 1.2 created this file. For more info see http://www.lyx.org/ \lyxformat 220 \textclass article \language english \inputencoding auto \fontscheme pslatex \graphics default \paperfontsize default \spacing single \papersize Default \paperpackage a4 \use_geometry 0 \use_amsmath 0 \use_natbib 0 \use_numerical_citations 0 \paperorientation portrait \secnumdepth 3 \tocdepth 3 \paragraph_separation skip \defskip medskip \quotes_language english \quotes_times 2 \papercolumns 1 \papersides 1 \paperpagestyle default \layout Title Lecture 13 \newline Concurrent Programming \layout Subsection* Thread/Process implementation \layout Standard A note on terminology: \layout Itemize \emph on process \emph default is typically (but not always) used in referring to execution contexts managed by the OS kernel. Sometimes you will hear \emph on heavy-weight process \emph default used to refer to an execution context together with an address space. \layout Itemize \emph on thread \emph default is typically (but not always) used in referring to execution contexts managed in user space. Sometimes you will hear the term \emph on light-weight processes \emph default used to refer to execution contexts that share an address space. The image of \emph on thread \emph default is of a very thin string (but we don't refer to heavy-weight processes as strings so the imagery isn't perfect). \layout Standard The book in Ch. 6 gives a description of typical approaches to implementing threads/processes in either OS-kernel or user space. Confusingly, a user-space implementation might be called a \emph on threads-kernel. \emph default A OS-kernel space implementation has to deal with addressability issues that don't arise in user space implementations, but otherwise the approach is the same. \layout Standard Each time a thread (or process) performs a thread operation (fork/join, interrupt, time-slice expiration) or a synchronization operation (monitor entry/exit, cond wait, cond notify, semaphore P/V) three main things have to happen: \layout Itemize the fate of the current thread must be decided and carried out -- it might be placed on a ready queue, or it might go onto the wait queue of a synchroniza tion object (monitor, condition, semaphore). Procedures running on the current thread's call stack usually carry out these operations. \layout Itemize the next thread to be run must be chosen. In the moment of the decision, this is the role of the \emph on dispatcher \emph default . In making its decision it will be guided by the data structures maintained by the \emph on scheduler. \emph default Again, procedures running on the current thread's call stack usually carry out this decision. \layout Itemize Finally, the processor must be switched to running the next thread, leaving the current thread in a state where it can be resumed. This involves saving all of the thread state held in processor registers into memory (typically onto the thread stack and into the thread control block) then loading the processor register for the next thread. \layout Subsection* Review \layout Standard Covered: 3 steps in handling every kernel entry: fate of current thread, choose next thread, switch threads. Fate of current thread depends on the operation it is performing -- return to ready queue, join some wait queue. How do we choose the next thread: FIFO queueing , priority scheduling, dynamic priority scheduling, weighted fair scheduling. \layout Subsection* Strict Priority Scheduling \layout Standard In strict priority scheduling, each thread is given a priority from some ordered set. (Often lower numbers are treated as higher priorities, but that is system dependent.) In a strict priority scheduler the dispatcher chooses the next task from the highest priority non-empty ready queue. Thus, the dispatcher ensures \layout Description priority-dispatching-property\SpecialChar ~ (UP\SpecialChar ~ version) the current running thread has priority at least as high as any runnable thread whenever the current thread is not running in the threads-kernel. \layout Standard Multiprocessor: with \emph on n \emph default processors there will be \emph on n \emph default running threads. The dispatcher tries to ensure \layout Description priority-dispatching-property\SpecialChar ~ (MP\SpecialChar ~ version) no runnable (but not running) thread has priority higher than the lowest priority running thread. \layout Standard On a uniprocessor, notice that a high priority thread will exclude all lower priority threads, but the same is not true on a multiprocessor. Also, on a uniprocessor, the priority-dispatching-property always holds (it's an invariant). But on a multi-processor the property is only a desired state: because processors schedule themselves and it takes time for rescheduling to happen, the priority dispatching property is not invariant on multiprocessors. \layout Standard Example: \layout LyX-Code Running task priorities: 6, 4 \layout LyX-Code The priority 6 running task makes a priority 5 task ready \layout LyX-Code (how?). Then until the other processor notices and acts on \layout LyX-Code the fact that there is now a priority 5 ready task, the MP \layout LyX-Code priority property will not hold. \layout Standard Lesson: \emph on thou shalt not rely on the strict priority property on multiprocessors. \layout Subsubsection* Priority Inversions \layout Standard Now consider the interaction of priorities with synchronization. Suppose a low priority thread holds a resource needed by a high priority thread. Clearly, the high priority thread will not be able to proceed until the low priority thread releases the resource. This is called a \emph on priority inversion \emph default . In a system with only two threads this is not a problem. In a system with additional threads at priority above that of the low priority thread it can be a \emph on big \emph default problem. In fact a thread at an intermediate priority level can cause the high priority thread to \emph on never \emph default make any progress. This is known as an \emph on unbounded priority inversion. \layout Standard Curing priority inversion problems in strict priority systems: a straightforward solution to priority inversions is to implement \emph on priority inheritance: \emph default when a thread waits on a lock, the priority of the current holder of the lock is temporarily boosted to that of the waiting process. \layout Standard Consider: how well does priority inheritance work for semaphores used in the passing-the-baton scenario? How well does it work for threads that wait on condition variables? \layout Subsubsection* Example: Mars lander \layout Standard The Mars pathfinder lander suffered a classic case of unbounded priority inversion soon after its landing. After the mission controllers discovered that the antenna system had much more bandwidth than anticipated they devoted some of the additional bandwidth to sending medium-priority data. This prevented a low-priority thread from releasing a semaphore needed by a high-priority thread in a timely fashion. Another high priority thread noticed that the first had not completed in time and repeatedly forced a system reset. \emph on Handout Wilner's description. \layout Subsubsection* Interaction of time slicing and Yield with priorities \layout Standard Last time in class we mentioned difficulties that arise if rogrammers have to include code to voluntarily switch tasks (yield). Time slicing (interrupting a running thread and forcing a switch to another ready thread) is a generally preferable model to the voluntary yield model. \layout Standard With strict priority scheduling neither time slicing nor voluntary yielding is adequate to ensure progress if priority inversions occur. Also, neither can arrange for a thread to reliably receive a few timeslices now and then. \layout Subsubsection* Ensuring progress in a strict priority scheduler by making it \begin_inset Quotes eld \end_inset less strict \begin_inset Quotes erd \end_inset . DirectedYield \layout Standard An interesting primitive to include in a threads-kernel is DirectedYield(tid). DirectedYield switches to the named thread regardless of which thread the priority computation would designate as being next. The beneficiary thread runs either to the end of the timeslice or until it blocks. A high priority thread that can inspect the ready queues can occasionally \begin_inset Quotes eld \end_inset donate \begin_inset Quotes erd \end_inset some cycles to each thread, thus eliminating unbounded priority inversion. \layout Standard No work has been done on quantifying the length of priority inversions under such a scheme. To me this trick feels too much like recovering from missing notifys by adding timeouts to be very satisfying. Nevertheless, it allowed us to fix a real problem in the GV system when the resources weren't available to fix the application code. We made a simple change to the thread kernel code to solve the problem. \layout Subsection* Dynamic Priority Scheduling \layout Standard Often used in time-sharing systems. Not so common in user-space thread libraries. In this scheme priorities are treated as advice. The system gives more resources to high priority threads than to low priority ones. Threads priorities are changed by the system depending on their resource use. Changes are typically intended to give \begin_inset Quotes eld \end_inset good performance \begin_inset Quotes erd \end_inset to \begin_inset Quotes eld \end_inset interactive threads \begin_inset Quotes erd \end_inset . I'm not aware of a good characterization of the performance one can expect from these schemes, but they have evolved to the point of being common and useful. \layout Standard Some systems such as NT and Solaris use a combined dynamic priority and strict priority system, with dynamic priority threads receiving service only after the needs of strict priority threads have been met. \layout Subsection* Weighted Scheduling \layout Standard Weighted scheduling attempts to reflect the importance of different threads by saying what fraction of the processor (or other resource) should be devoted to each thread. In weighted scheduling the goal is to give every thread as much processor time as it needs. This is unlike priority scheduling which equates \begin_inset Quotes eld \end_inset higher-priority \begin_inset Quotes erd \end_inset with \begin_inset Quotes eld \end_inset ability to exclude others \begin_inset Quotes erd \end_inset . \layout Standard Example: threads have weights 6, 3, 1: the fraction of the processor received by each thread is \begin_inset Formula $w_{i}/\sum w_{j}$ \end_inset . In our example, the first thread receives 60%, the second 30% and the third 10%. Research topic: characterize weighted scheduling when threads are interdependen t (interact through synchronization primitives). \layout Standard Implementations: randomized, weighted perfect shuffle, Bresenham line drawing. \layout Standard Randomized: pick a random number \emph on r \emph default in [0.. \begin_inset Formula $\sum w_{j}-1$ \end_inset ]. If \emph on r \emph default < \begin_inset Formula $w_{1}$ \end_inset pick thread 1, if \begin_inset Formula $w_{1}\le r