Скачать презентацию Semaphores Operating System support for concurrency Motivation

be67475d9c28fce5d878dc8fc001600a.ppt

• Количество слайдов: 34

Semaphores Operating System support for concurrency

Motivation • Goal is to eliminate busy waiting – See Sec. 2. 3. 4, p. 108 • Consider a simplified version of the semaphore first: – Sleep – block if waiting to get into critical section – Wake-up – unblock, or move from blocked to ready • A little too simple – Vulnerable to race conditions…

Sleep and Wakeup Producer-consumer problem with fatal race condition

Semaphores • A semaphore S is an integer variable that, apart from initialization, is accessed only through two standard atomic operations wait (down) and signal (up). – Atomic – S may be • binary – used to enforce mutual exclusion (mutex) or synchronize processes; • counting – used to synchronize processes

About semaphores. . . • Invented by Edsgar Dijkstra in 1965 – He was a famous Dutch computer scientist who passed away in 2004… • Generalized locking mechanisms – They count the number of saved wake-ups – May be implemented in hardware or software • Got milk? example : wait(S) [or down(S)] if no milk then buy milk signal(S) [or up(S)]

wait & signal operations wait (S): while S <= 0 do no-op; S = S - 1; as soon as S > 0 signal (S): S = S + 1; • S is initialized to a value >= 1 why not 0? when >0? • wait & signal are executed atomically – if one process is modifying the semaphore, no other process can do so. – in the wait, the testing of the semaphore and the modification is un-interruptible.

Semaphores are data structures • They have the following basic operations associated with them: – initialize – wait – signal

Recall the n-process Critical Section problem • We can use a semaphore to guarantee simple mutual exclusion. S is initialized to 1, and the code for each process is as follows: repeat wait (S) critical section signal (S) remainder section until false; Easier than the bakery algorithm!

BACI implementation of semaphores • semaphore S; declares S to be type semaphore • initialsem(S, value) initializes semaphore S to a given value • signal(S) • wait(S)

Synchronizing processes • Suppose p 1 contains statement s 1 and p 2 contains statement s 2 – s 2 can execute only after s 1 has completed – it’s a synchronization issue • Use semaphore sync, initialized to 0: in p 1: s 1 in p 2: wait (sync) signal (sync) s 2

Aren’t we still busy waiting? • All solutions we’ve seen so far spend a lot of time doing nothing: while. . . do no-op; – This wastes CPU cycles that would otherwise be available for other processes • We address the problem of busy waiting by modifying the semaphore so that wait & signal enable a process to block itself rather than spin its wheels.

Recall process states READY RUNNING BLOCKED We will complicate this model slightly

The block operation • Puts the process (thread) in a semaphore’s queue. • Process state changes from running to blocked. – It’s blocked waiting on the semaphore • Now another process or thread can execute. • The blocked process will become ready when some other process executes a signal operation on the same semaphore. – Then, the process is placed in the ready queue.

How this is implemented • Define semaphore as a class object or struct: value List of waiting processes • When a process must wait on a semaphore, it is added to its list of blocked processes. A signal operation removes one process from the list and wakes it up.

Operations wait & signal are now more complex wait(S) S. value : = S. value - 1; if S. value < 0 then { add this process to S. list; block; } signal(S) S. value : = S. value + 1; if S. value <= 0 then { remove a process from S. list; wakeup(process); } block & wakeup are provided by the OS (system calls)

Some observations • The order in which processes are awakened depends on the CPU scheduling algorithm (not always FCFS) • Always remember that wait & signal are executed atomically. – So, no two processes can execute wait or signal operations on the same semaphore at the same time. • If we have only one processor, we can inhibit interrupts during the time the wait and signal operations are executing. This will not work in a multiprocessing environment.

Some more observations • Semaphore values in this later definition can actually become negative. – What would a negative value signify? • Busy waiting has not actually been eliminated, just mitigated – it’s been moved to the wait & signal operations – why is this preferable?

Deadlock • When we use a semaphore with a waiting queue, we may create a situation in which two or more processes are waiting for an event (a signal operation) that can be caused only by one of the waiting processes. When such a state is reached, these processes are said to be deadlocked. • Formal def of deadlock in Chapter 3

Starvation • Another related problem is indefinite postponement or starvation. This happens when processes must wait indefinitely and may occur if we add processes to (and remove them from) the semaphore list in LIFO order.

Some Classical Synchronization Problems (Sec. 2. 4) • These scenarios are used to test synchronization schemes: – Bounded Buffer – Readers Writers – Dining Philosophers – Sleeping Barber • Solutions here rely on semaphores, but next time we’ll see another approach.

Examples of producer-consumer processes Producer • Output process stores characters in a buffer • Assembler process produces object code Consumer • Printer driver reads characters from buffer • Linker/loader process forms object code into a run unit

Bounded Buffer (Producer. Consumer) Problem • Assume a buffer of size N. • mutex (initialized to 1) – Provides mutual exclusion. • empty and full (both semaphores) count the number of buffers that are empty and full resp. Empty initialized to N and full to 0 – Used for synchronizing the processes

Producer Consumer problem

Readers and Writers • If two (or more) readers access the shared file at the same time, there is no problem. • However, we cannot allow a writer to access the shared file at the same time as another process (either a reader or writer). Why? • So we give the writers exclusive access to the file. • BUT, no reader will be kept waiting unless a writer has already gained access to the file • So, readers have a certain degree of priority over writers. . .

The solution • Initialize an integer variable rc to 0 – rc is used to count the number of readers – Mutual exclusion is required for any reader process to update rc • Initialize two semaphores, mutex (mutual exclusion while updating rc) and db (mutual exclusion for the writers), both to 1.

The Dining Philosophers Models allocating several resources among several processes. Correct solutions are free of both deadlock and starvation.

The problem • We have 5 (or more) philosophers who eat & think all day. They all sit around a circular table that contains 5 plates and 5 single chopsticks, placed one between each plate. • In order to eat, a philosopher needs 2 chopsticks, the one to the left of her plate and the one to the right. • When she finishes eating she puts down both chopsticks.

A simple but flawed solution • Initialize all elements of semaphore array chopstick to 1. (chopstick[0]. . . chopstick[4]) repeat wait (chopstick[i]); wait (chopstick[(i+1) % 5]); eat signal (chopstick[i]); signal (chopstick[(i+1) % 5]); think; until false;

What can we do to fix this? • Allow at most 4 philosophers to sit at the table set for five the same time • Allow a philosopher to pick up her chopsticks only if both are available. • Use an asymmetric solution i. e. , an odd philosopher picks up the left and then the right, an even philosopher picks up the right and then the left.

Dining Philosophers solution Part 1

Dining Philosophers solution Part 2

The Sleeping Barber Problem

The Sleeping Barber solution