570 likes | 591 Vues
Synchronization 2: semaphores and more…. What’s wrong with busy waiting?. Doesn‘t make sense for Uni -processor Wastes CPU time May cause priority inversion and deadlock. The mutual exclusion algorithms we saw used busy-waiting. What’s wrong with that?.
E N D
Synchronization 2: semaphoresand more… Operating Systems, 2011, Danny Hendler & Amnon Meisels
What’s wrong with busy waiting? • Doesn‘t make sense for Uni-processor • Wastes CPU time • May cause priority inversion and deadlock The mutual exclusion algorithms we saw used busy-waiting. What’s wrong with that? Operating Systems, 2011, Danny Hendler & Amnon Meisels
Priority inversion and deadlock result What’s wrong with busy waiting? Busy waiting may cause priority-inversion and deadlock • Process A's priority is higher than process B's • Process B enters the CS • Process A needs to enter the CS, busy-waits for B to exit the CS • Process B cannot execute as long as the higher-priority process A is executing/ready Operating Systems, 2011, Danny Hendler & Amnon Meisels
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, 2011, Danny Hendler & Amnon Meisels
Synchronization Constructs– Semaphores (Dijkstra ‘68) Two operations define a semaphoreS: DOWN(S) p(s) while(s <= 0); s = s - 1; UP(S) v(s) s = s + 1; • Operations on the counter are performed indivisibly Sis non-negative • but this description busy-waits… Operating Systems, 2011, Danny Hendler & Amnon Meisels
Semaphores (Dijkstra ‘68) Two atomic operations are supported by a semaphoreS: up(S) [the `v’ operation] • S++ • If there are blocked processes, wake-up one of them down(S) [the ‘p’ operation] • If S≤0 the process is blocked. It will resume execution only when awakened by an up(S) operation • S-- • S is non-negative • What exactly does “atomic” mean ?? Operating Systems, 2011, Danny Hendler & Amnon Meisels
A single up() operation for 2 down()s Wrong non negative Semaphore Lines of code are executed asynchronously • S=0 and process A performs down(S) – A is blocked • Process B performs up(S) – S=1 A is ready • Process C performs down(S) – S=0 & C proceeds • Process A gets a time-slice and proceeds – S=0 Operating Systems, 2011, Danny Hendler & Amnon Meisels
Semaphores (Dijkstra ‘68) Two atomic operations are supported by a semaphoreS: up(S) [the `v’ operation] • If there are blocked processes, wake-up one of them • else S++ down(S) [the ‘p’ operation] • If S≤0 the process is blocked. It will resume execution only when awakened by an up(S) operation • else S-- • S is non-negative • Supported by Windows, Unix, … Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing mutex with semaphores Shared data: semaphorelock; /* initially lock = 1 down(lock) Critical section up(lock) Yes Does the algorithm satisfy mutex? Does it satisfy deadlock-freedom? Does it satisfy starvation-freedom? Yes Depends… Operating Systems, 2011, Danny Hendler & Amnon Meisels
Synchronization with semaphores Three processes p1; p2; p3 semaphores s1 = 1, s2 = 0; p1p2p3 down(s1); down(s2); down(s2); A B C up(s2); up(s2); up(s1); Which execution orderings of A, B, C, are possible? (A B* C)* Operating Systems, 2011, Danny Hendler & Amnon Meisels
No guarantee for correct synchronization P0P1 down(S); down(Q); down(Q); down(S); move1move2 up(S); up(Q); up(Q) up(S); 1 1 • Example: move money between two accounts which are protected by semaphores S and Q Does this work? Deadlock! Operating Systems, 2011, Danny Hendler & Amnon Meisels
Negative-valued semaphores up(S) • S++ • If there are blocked processes (i.e. S<0), wake-up one of them Two atomic operations are supported by a semaphoreS: down(S) • S-- • If S<0 the process is blocked. It will resume execution only when S is non-negative -3 • If S is negative, then there are –S blocked processes Operating Systems, 2011, Danny Hendler & Amnon Meisels
Negative semaphore Implementation type semaphore = record value: integer; L: list of process; end; -3 down(S):S.value--; if (S.value < 0) { add this process to S.L;sleep; } up(S): S.value++; if (S.value <= 0) { remove a process P from S.L;wakeup(P); } Operating Systems, 2011, Danny Hendler & Amnon Meisels
out in Producer-Consumer Problem • Paradigm for cooperating processes, • producer process produces information that is consumed by a consumer process • Two versions • unbounded-bufferplaces no practical limit on the size of the buffer • bounded-bufferassumes that there is a fixed buffer size buffer Operating Systems, 2011, Danny Hendler & Amnon Meisels
Bounded Buffer buffer 0 1 2 item1 2 Out item2 3 item3 consumer 4 producer item4 5 6 In 7 Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementation using semaphores • Two processes or more use a shared buffer in memory • The buffer is finite (e.g., bounded) • The producer writes to the buffer and the consumer reads from it • A full buffer stops the producer • An empty buffer stops the consumer Operating Systems, 2011, Danny Hendler & Amnon Meisels
Producer-Consumer implementation with semaphores #define N 100 /* Buffer size */ typedefintsemaphore; semaphoremutex = 1; /* access control to critical section */ semaphore empty = N; /* counts empty buffer slots */ semaphore full = 0; /* counts full slots */ void producer(void) { int item; while(TRUE) { produce_item(&item); /* generate something... */ down(&empty); /* decrement count of empty */ down(&mutex); /* enter critical section */ enter_item(item); /* insert into buffer */ up(&mutex); /* leave critical section */ up(&full); /* increment count of full slots */ } } Operating Systems, 2011, Danny Hendler & Amnon Meisels
Producer-Consumer implementation with semaphores void consumer(void){int item; while(TRUE) {down(&full); /* decrement count of full */down(&mutex); /* enter critical section */remove_item(&item); /* take item from buffer) */up(&mutex); /* leave critical section */up(&empty); /* update count of empty */consume_item(item); /* do something... */ }} Comment:up() and down() are atomic operations Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a binary semaphore with TSL • In user space, one can use TSL (test-set-lock) mutex_lock: TSL REG, mutex CMP REG, #0 JZE ok | the equivalent ofenter_region CALL thread_yield JMP mutex_lock ok: RET mutex_unlock: MOV mutex, #0 RET also called a Spin-lock Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a negative semaphore with TSL type semaphore = record value, flag: integer; L: list of process; end; -3 down(S):repeat until test-and-set(S.flag) S.value--; if (S.value < 0) { add this process to S.L;S.flag=0sleep; }else S.flag=0 up(S):repeat until test-and-set(S.flag)S.value++; if (S.value <= 0) { remove a process P from S.L;wakeup(P); } S.flag=0 Operating Systems, 2011, Danny Hendler & Amnon Meisels
More on semaphore implementation • TSL implementation can work for multi-processors • On a uni-processor, may be implemented by disabling interrupts • On a multi-processor, we can use spin-lock mutual exclusion to protect semaphore access Why is this better than busy-waiting in the 1st place? Busy-waiting is now guaranteed to be very short Operating Systems, 2011, Danny Hendler & Amnon Meisels
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, 2011, Danny Hendler & Amnon Meisels
Binary Semaphore • Assumes only values 0 or 1 • Wait blocks if semaphore=0 • Signal either wakes up a waiting thread, if there is one, or sets value to 1 • How can wakeup signals be accumulated (for the bounded buffer, for example) Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a counting semaphore with binary semaphores: take 1 down(S): down(S1); S.value--; if(S.value < 0){ up(S1); // L1 down(S2); } //L2 else up(S1); binary-semaphore S1, S2 initially 1; S.value initially 1 up(S): down(S1); S.value++; if(S.value≤ 0) up(S2); up(S1) This code does not work Operating Systems, 2011, Danny Hendler & Amnon Meisels
Race condition for counting semaphore take 1 • Processes Q1 – Q4 perform down(S), Q2 – Q4 are preempted between lines L1 and L2: the value of the counting semaphore is now -3 • Processes Q5-Q7 now perform up(S): the value of the counting semaphore is now 0 • Now, Q2-Q4 wake-up in turn and perform line L2 (down S2) • Q2 runs but Q3-Q4 block. There is a discrepancy between the value of S and the number of processes waiting on it Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a counting semaphore with binary semaphores: take 2 down(S): down(S1); S.value--; if(S.value < 0){ up(S1); //L1 down(S2); } //L2 up(S1); binary-semaphore S1=1, S2=0; S.value initially 1 up(S): down(S1); S.value++; if(S.value ≤ 0) up(S2); else up(S1) Does this code work? Operating Systems, 2011, Danny Hendler & Amnon Meisels
The effect of the added ‘else’ • up(S1) is performed by up(S) only if no process waits on S2 • Q5 leaves up(S) without releasing S1 • Q6 cannot enter the critical section that protects the counter • It can only do so after one of Q2-Q4 releases S1 • This generates a “lock-step” situation • The critical section that protects the counter is entered alternately by a producer or a consumer Operating Systems, 2011, Danny Hendler & Amnon Meisels
Recall the bounded-buffer algorithm void consumer(void){int item; while(TRUE) {down(&full); down(&mutex); remove_item(&item);up(&mutex); up(&empty); consume_item(item); }} #define N 100 typedefintsemaphore; semaphoremutex = 1; semaphoreempty = N; semaphore full = 0; void producer(void) { int item; while(TRUE) { produce_item(&item); down(&empty); down(&mutex); enter_item(item); up(&mutex); up(&full); } } Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario Consider a Bounded buffer of 5 slots. Assume there are 6 processes each filling five slots in turn. 1 2 Empty.Value = 5 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 1. five slots are filled by the first producer 1 2 Empty.Value = 0 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 1. The second producer is blocked 1 2 Empty.Value = -1 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 1. The third producer is blocked 1 2 Empty.Value = -2 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 1. The fourth producer is blocked 1 2 Empty.Value = -3 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 1. The fifth producer is blocked 1 2 Empty.Value = -4 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 2. All blocked producers are waiting on S2 1 2 Empty.Value = -5 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 3. The consumer consumes an item and is blocked on Empty.S1 until a producer adds an item. 1 2 Empty.Value = -5 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 3. The consumer consumes an item and is blocked on S1 , one producer adds an item. 1 2 Empty.Value = -4 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 4. Consumer must consume, only then another producer wakes up and produces an item 1 2 Empty.Value = -3 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 4. Same as in step 3. 1 2 Empty.Value = -2 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
A Problematic Scheduling Scenario 5. And again… 1 2 Empty.Value = -1 3 4 5 6 Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a counting semaphore with binary semaphores: take 3 (P.A. Kearns, 1988) down(S) down(S1); S.value--; if(S.value < 0){ up(S1); //L1 down(S2); //L2 down(S1); S.wake--; //L3 if(S.wake > 0) then up(S2);} //L3 up(S1); binary-semaphore S1=1, S2=0, value initially 1, integer wake=0 up(S): down(S1); S.value++; if(S.value <= 0) { S.wake++; up(S2); } up(S1); Does THIS work? Operating Systems, 2011, Danny Hendler & Amnon Meisels
Correctness arguments (Kearns)… • The counter S.wake is used when processes performing down(S) are preempted between lines L1 and L2 • In such a case, up(S2) performed by processes during up(S) have no effect • However, these processes accumulate their waking signals on the (protected) counter S.wake • After preemption is over, any single process that wakes up from its block on down(S2) checks the value of S.wake • The check is again protected • For each count of the wake-up signals, the awakened process performs the up(S2) (in line L3) • Each re-scheduled process wakes up the next one Operating Systems, 2011, Danny Hendler & Amnon Meisels
Kearns' algorithm is wrong • Processes P0..P8 perform down(S), P1..P8 are preempted just before line L2 of the operation • Processes P9..P12 perform up(S) and their up(S2) lines release, say, P1..P4 • 4 processes are waiting on S2 and S.wake = 4 • Processes P1..P4 are ready, just before lines L3 • Each of P1..P4 will decrement S.wake in its turn, check that it's positive and signal one of P5..P8 • Four up(S) have released 8 down(S) Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a counting semaphore with binary semaphores: take 4 (Hemmendinger, 1989) down(S) down(S1); S.value--; if(S.value < 0){ up(S1); down(S2); down(S1); S.wake--; if(S.wake > 0) then up(S2);} // L3 up(S1); binary-semaphore S1=1, S2=0, integer value =1, integer wake=0 up(S): down(S1); S.value++; if(S.value <= 0) { S.wake++; if (S.wake == 1) up(S2); } up(S1); This works Operating Systems, 2011, Danny Hendler & Amnon Meisels
Implementing a counting semaphore with binary semaphores: take 5(Barz, 1983) down(S) down(S2); down(S1); S.value--; if (S.value>0) then up(S2); up(S1); binary-semaphore S1=1, S2=min(1, init_value), value=init_value up(S): down(S1); S.value++; if(S.value == 1) { up(S2); } up(S1); This works, is simpler, and was published earlier(!)… Can we switch the order of downs in down(S)? Operating Systems, 2011, Danny Hendler & Amnon Meisels
Correctness arguments… • The critical section is guarded by S1 and each of the operations down(S) and up(S) uses it to correctly update the value of S.value • After updating (and inside the critical section) both operations release the S2 semaphore only if value is positive • S.value is never negative, because any process performing down(S) is blocked at S2 • Signals cannot be 'wasted' Operating Systems, 2011, Danny Hendler & Amnon Meisels
Fairness of semaphores • Order of releasing blocked processes: • Fair • Processes are not allowed multiple entries if others are waiting • Another option: • Open competition each time the lock is free • Imitating the Java ‘wait’ ‘notify’ mechanism • Starvation is possible Operating Systems, 2011, Danny Hendler & Amnon Meisels
Counting and Binary semaphores(open contest) binary-semaphore S1 =1, S2=0; int S.value=k, S.wait=0, S.wake=0 down(S): down(S1); while(S.value == 0){ S.wait++; up(S1); down(S2); down(S1); S.wait--; S.wake--; } if(S.wake > 0) then up(S2); S.value--; up(S1); up(S): down(S1); if (S.wait > 0 && S.wake < S.wait) { S.wake++; if (S.wake==1) up(S2); } S.value++ up(S1) Operating Systems, 2011, Danny Hendler & Amnon Meisels
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, 2011, Danny Hendler & Amnon Meisels