550 likes | 569 Views
Explore the complexities of synchronization mechanisms like semaphores and mutual exclusion algorithms in Operating Systems. Learn the dangers of busy waiting, possible deadlock scenarios, and efficient synchronization methods. Dive into semaphore operations, producer/consumer problem, and event handling for optimal system performance.
E N D
Synchronization: semaphoresand some more stuff Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
What's wrong with busy waiting? • Doesn't make sense for uni-processor • May cause deadlock • Wastes CPU time • But may be efficient if waiting-time is short The mutual exclusion algorithms we saw used busy-waiting. What’s wrong with that? Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Deadlock results What's wrong with busy waiting? Busy waiting may cause 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Semaphores 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 after it is woken-up • Else S-- • S is non-negative • Supported by Windows, Unix, … Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Semaphores: is the following correct? up(S) [the 'v' operation] • S++ • If there are blocked processes, wake-up one of them Two atomic operations are supported by a semaphoreS: down(S) [the 'p' operation] • If S≤0 the process is blocked. It will resume execution only after it is woken-up • S-- Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A single up() freed 2 down()s Pseudo-code in previous slide is wrong Consider the following bad scneario: • 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=-1 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
More on synchronization using 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 orders of A, B, C, are possible? (A B* C)* Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
No guarantee for correct synchronization(when multiple semaphores/locks are used) 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Negative semaphore Implementation type semaphore = record value: integer; L: list of process; end; -3 L atomic down(S):S.value--; if (S.value < 0) { add this process to S.L;sleep; } atomic up(S): S.value++; if (S.value <= 0) { remove a process P from S.L;wakeup(P); } Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a spin-lock with TSL (test-set-lock) mutex_lock: TSL REG, mutex CMP REG, #0 JZE ok CALL thread_yield JMP mutex_lock ok: RET mutex_unlock: MOV mutex, #0 RET Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a negative semaphore with TSL -3 type semaphore = record value, flag: integer; L: list of process; end; L 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 Any problem with this code? In down(), resetting flag and sleeping should be atomic. Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
More on semaphore implementation • On a uni-processor, disabling interrupts may be used • TSL implementation works for multi-processors • On a multi-processor, we can use spin-lock mutual exclusion to protect semaphore access Why is this better than busy-waiting in the first place? Busy-waiting is now guaranteed to be very short Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Bounded Buffer buffer 0 1 2 item1 2 Out item2 3 item3 consumer 4 producer item4 5 6 In 7 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementation using semaphores • Two processes or more use a shared buffer in memory • The buffer has finite size(i.e., it is 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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... */ }} Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Binary Semaphore • Assumes only values 0 or 1 • Wait blocks if semaphore=0 • Signal (up operation) either wakes up a waiting process, if there is one, or sets value to 1 (if value is already 1, signal is “wasted”) • How can we implement a counting semaphore by using binary semaphores? Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a counting semaphore with binary semaphores (user space): take 1 down(S): down(S1); S.value--; if(S.value < 0){ up(S1); down(S2); } else up(S1); binary-semaphore S1 initially 1, S2 initially 0, S.value initially 1 up(S): down(S1); S.value++; if(S.value≤ 0) up(S2); up(S1) L1: L2: This code does not work. Why? Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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. 3 down( ) operations should have been “permitted”, only 1 was Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a counting semaphore with binary semaphores (user space): take 2 down(S): down(S1); S.value--; if(S.value < 0){ up(S1); //L1 down(S2); } //L2 up(S1); binary-semaphore S1 initially 1, S2 initially 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
The effect of the changes 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: an up(), a down(), an up()… • The critical section that protects the counter is entered alternately by a producer or a consumer Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Recall the bounded-buffer algorithm #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); } } void consumer(void){int item; while(TRUE) {down(&full); down(&mutex); remove_item(&item);up(&mutex); up(&empty);consume_item(item); }} Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 1. five slots are filled by the first producer 1 2 Empty.Value = 0 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 1. The second producer is blocked 1 2 Empty.Value = -1 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 1. The third producer is blocked 1 2 Empty.Value = -2 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 1. The fourth producer is blocked 1 2 Empty.Value = -3 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 1. The fifth producer is blocked 1 2 Empty.Value = -4 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 2. All blocked producers are waiting on S2 1 2 Empty.Value = -5 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 4. Same as in step 3. 1 2 Empty.Value = -2 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario 5. And again… 1 2 Empty.Value = -1 3 4 5 6 Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a counting semaphore with binary semaphores (user space): 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--; 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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) has 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Kearns' algorithm is wrong • Processes P0..P7 perform down(S), P0 goes through, P1..P7 go to sleep after performing line L2 of the operation • Processes P8..P11 perform up(S) and their up(S2) operations release, say, P1..P4 • Processes P5, P6, P7 are still waiting on S2 and S.wake = 4 • Processes P1..P4 are ready, just before line L3 • Each of P1..P3 will decrement S.wake in its turn, check that it's positive and signal one of P5..P7 • Four up operations have released 7 down operations Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a counting semaphore with binary semaphores (user space): 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 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Implementing a counting semaphore with binary semaphores (user space): 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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Fairness of semaphores • Order of releasing blocked processes: • Weak – up() performing process enters after (one of the) blocked processes • Strong – An upper bound on the number of entries of process that performed up() if others are waiting • Unfair: • No guarantee about the number of times the up() performing process enters before the blocked • Open competition each time the lock is free • Imitating the Java 'wait' 'notify' mechanism • Or the spin-lock of XV6… Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Outline • Semaphores and the producer/consumer problem • Counting semaphores from binary semaphores • Event counters and message passing synchronization Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Event Counters • Integer counters with three operations: • Advance(E): increment E by 1, wake up relevant sleepers • Await(E,v): wait until E ≥ v. Sleep if E < v • Read(E): return the current value of E • Counter value is ever increasing • The Read() operation is not required for the bounded-buffer implementation in the next slide Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
producer-consumer with Event Counters(for a single producer and a single consumer) #define N 100typedef int event_counter; event_counter in = 0; /* counts inserted items */event_counter out = 0; /* items removed from buffer */ void producer(void){int item, sequence = 0; while(TRUE) { produce_item(&item);sequence = sequence + 1; /* counts items produced */await(out, sequence - N); /* wait for room in buffer */enter_item(item); /* insert into buffer */advance(&in); /* inform consumer */ }} Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky