Upload
others
View
9
Download
0
Embed Size (px)
Citation preview
Synchronization: semaphoresand some more stuff
1Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
What's wrong with busy waiting?
❑ Doesn't make sense for uni-processoro May cause deadlock
❑ Wastes CPU timeo But may be efficient if waiting-time is short
The mutual exclusion algorithms we saw used busy-waiting. What’s wrong with that?
2Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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
Deadlock results
3Operating 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
4Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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--
Two atomic operations are supported by a semaphore S:
❑ S is non-negative
❑ Supported by Windows, Unix, …
5Operating 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
down(S) [the 'p' operation]❑ If S≤0 the process is blocked. It
will resume execution only after it is woken-up
❑ S--
Two atomic operations are supported by a semaphore S:
6Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
7
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
A single up() freed 2 down()s
Operating Systems, 2011, Danny Hendler & Amnon Meisels
Pseudo-code in previous slide is wrong
Implementing mutex with semaphores
Shared data: semaphore lock; /* initially lock = 1 */
down(lock)
Critical section
up(lock)
Does the algorithm satisfy mutex?
Does it satisfy deadlock-freedom?
Does it satisfy starvation-freedom?
YesYes
Depends…8Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Semaphore as a General Synchronization ToolSemaphore as a General Synchronization Tool
❑ Execute B in Pj only after A executed in Pi
❑ Use semaphore flag initialized to 0
❑ Code:
Pi Pj
… …
A down(flag)
up(flag) B
❑ Execute B in Pj only after A executed in Pi
❑ Use semaphore flag initialized to 0
❑ Code:
Pi Pj
… …
A down(flag)
up(flag) B
0
time
9Operating 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;
p1 p2 p3down(s1); down(s2); down(s2);A B Cup(s2); up(s2); up(s1);
Which execution orders of A, B, C, are possible?
(A B* C)*
10Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
P0 P1
down(S); down(Q);
down(Q); down(S);
move1 move2
up(S); up(Q);
up(Q) up(S);
1
1
❑ Example: move money between two accounts which are protected by semaphores S and Q
No guarantee for correct synchronization(when multiple semaphores/locks are used)
Does this work?
Deadlock!
11Operating 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
-3
down(S)
❑ S--
❑ If S<0 the process is blocked. It will resume execution only when S is non-negative
Two atomic operations are supported by a semaphore S:
❑ If S is negative, then there are –S blocked processes
12Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
type semaphore = record
value: integer;
L: list of process;
end;
Negative semaphore Implementation
-3
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);
}13Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
L
Implementing a spin-lock with TSL (test-set-lock)
mutex_lock:TSL REG, mutexCMP REG, #0JZE okCALL thread_yieldJMP mutex_lock
ok:RET
mutex_unlock:MOV mutex, #0RET
14Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
type semaphore = recordvalue, 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
Implementing a negative semaphore with TSL
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
15Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
L
Any problem with this code?
In down(), resetting flag and sleeping should be atomic.
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
16Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Producer-Consumer Problem
❑ Paradigm for cooperating processes,
• producer process produces information that is consumed by a consumer process
❑ Two versions
• unbounded-buffer places no practical limit on the size of the buffer
• bounded-buffer assumes that there is a fixed buffer size
buf
fer
in
out
17Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
2
6
Out
In
item1
item4
item3
item2
consumer
0
buffer
producer
Bounded Buffer
1
2
3
4
5
7
18Operating 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
19Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Producer-Consumer implementation with semaphores
#define N 100 /* Buffer size */
typedef int semaphore;
semaphore mutex = 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 */
} } 20Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
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... */
}}
21Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Producer-Consumer implementation with semaphores
Outline
❑ Semaphores and the producer/consumer problem
❑ Counting semaphores from binary semaphores
❑ Event counters and message passing synchronization
22Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
23Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
❑ 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?
Binary Semaphore
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)
This code does not work. Why?
24Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
L1:
L2:
Race condition for counting semaphore take 1
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
2. Processes Q5-Q7 now perform up(S): the value of the counting semaphore
is now 0
3. Now, Q2-Q4 wake-up in turn and perform line L2 (down S2)
4. Q2 runs but Q3-Q4 block.
25Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
3 down( ) operations should have been “permitted”, only 1 was
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);
up(S):
down(S1);
S.value++;
if(S.value ≤ 0)
up(S2);
else
up(S1)
Does this code work?
26Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
binary-semaphore S1 initially 1, S2 initially 0, S.value initially 1
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
The effect of the changes
27Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Recall the bounded-buffer algorithm
#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = 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);
}}
28Operating 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.
Empty.Value = 521
3 4
5 6
29Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
1. five slots are filled by the first producer
Empty.Value = 021
3 4
5 6
30Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
1. The second producer is blocked
Empty.Value = -121
3 4
5 6
31Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
1. The third producer is blocked
Empty.Value = -221
3 4
5 6
32Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
1. The fourth producer is blocked
Empty.Value = -321
3 4
5 6
33Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
1. The fifth producer is blocked
Empty.Value = -421
3 4
5 6
34Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
2. All blocked producers are waiting on S2
Empty.Value = -521
3 4
5 6
35Operating 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.
Empty.Value = -521
3 4
5 6
36Operating 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.
Empty.Value = -421
3 4
5 6
37Operating 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
Empty.Value = -321
3 4
5 6
38Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
4. Same as in step 3.
Empty.Value = -221
3 4
5 6
39Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
A Problematic Scheduling Scenario
5. And again…
Empty.Value = -121
3 4
5 6
40Operating 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);
up(S):down(S1);S.value++;if(S.value <= 0) {
S.wake++;up(S2); }
up(S1);
binary-semaphore S1=1, S2=0, value initially 1, integer wake=0
Does THIS work?
41Operating 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
42Operating 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
43Operating 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);
up(S):down(S1);S.value++;if(S.value <= 0) {
S.wake++;if (S.wake == 1)
up(S2); }up(S1);
binary-semaphore S1=1, S2=0, integer wake=0
This works
44Operating 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);
up(S):
down(S1);
S.value++;
if(S.value == 1) {
up(S2); }
up(S1);
binary-semaphore S1=1, S2=min(1, init_value), value=init_value
This works, is simpler, and was published earlier(!)… Can we switch the order of downs in down(S)?
45Operating 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'
46Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Fairness of semaphores
❑ Order of releasing blocked processes:
o Weak – up() performing process enters after (one of the) blocked processes
o Strong – An upper bound on the number of entries of process that performed up() if others are waiting
❑ Unfair:
o No guarantee about the number of times the up() performing process enters before the blocked
o Open competition each time the lock is free
o Imitating the Java 'wait' 'notify' mechanism
o Or the spin-lock of XV6…
47Operating 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
48Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Event Counters
❑ Integer counters with three operations:
o Advance(E): increment E by 1, wake up relevant sleepers
o Await(E,v): wait until E ≥ v. Sleep if E < v
o 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
49Operating 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 */
}}
50Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Event counters (producer-consumer)
void consumer(void){
int item, sequence = 0;
while(TRUE) {sequence = sequence + 1; /* count items consumed */
await(in, sequence); /* wait for item */
remove_item(&item); /* take item from buffer */
advance(&out); /* inform producer */
consume_item(item);}
}
51Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Message Passing – no shared memory
❑ In a multi-processor system without shared memory, synchronization can be implemented by message passing
❑ Implementation issues:
o Acknowledgements may be required (messages may be lost)
o Message sequence numbers required to avoid message duplication
o Unique process addresses across CPUs (domains..)
o Authentication (validate sender’s identity, a multi-machine environment…)
❑ Two main functions:
o send(destination, &message);
o receive(source, &message) block while waiting...
52Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
void consumer(void){int item, i;message m;
for(i = 0; i < N; i++) send(producer, &m); /* send N empties */
while(TRUE) {receive(producer, &m); /* get message with item */extract_item(&m, &item);send(producer, &m); /* send an empty reply */consume_item(item);
}}
53Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Producer-consumer using message passing
#define N 100
#define MSIZE 4 /* message size */
typedef int message(MSIZE);
void producer(void){
int item;message m; /* message buffer */
while(TRUE) {produce_item(&item);receive(consumer, &m); /*wait for an empty */construct_message(&m, item);send(consumer, &m); /* send item */
}}
54Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky
Producer-consumer using message passing (continued)
Message passing variations
❑ Messages can be addressed to a process address or to a mailbox
o Mailboxes are generated with some capacity. When sending a message to a full
mailbox, a process blocks
o Buffer management done by mailbox
❑ Unix pipes - a generalization of messages … no fixed size message (blocking
receive)
❑ If no buffer is maintained by the system, then send and receive must run in
lock-step. Example: Unix rendezvous
55Operating Systems, Spring 2019, I. Dinur , D. Hendler and M. Kogan-Sadetsky