Synchronization

advertisement
Synchronization: semaphores
and some more stuff
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
1
What's wrong with busy waiting?
The mutual exclusion algorithms we saw used
busy-waiting. What’s wrong with that?
 Doesn't make sense for uni-processor
o May cause priority inversion and deadlock
 Wastes CPU time
o But is efficient if waiting-time is short
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
2
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
Priority inversion and deadlock result
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
3
Outline
 Semaphores and the producer/consumer problem
 Counting semaphores from binary semaphores
 Event counters and message passing synchronization
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
4
Semaphores
Two atomic operations are supported by a semaphore 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--
up(S) [the `v’ operation]
 If there are blocked
processes, wake-up one of
them
 Else S++
 S is non-negative
 Supported by Windows, Unix, …
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
5
Semaphores: is the following correct?
Two atomic operations are supported by a semaphore S:
down(S) [the ‘p’ operation]


If S≤0 the process is blocked. It
will resume execution only after
it is woken-up
S--
up(S) [the `v’ operation]
 S++
 If there are blocked
processes, wake-up one of
them
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
6
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=0
A single up() freed 2 down()s
Operating Systems, 2011, Danny Hendler & Amnon Meisels
7
Implementing mutex with semaphores
Shared data: semaphore lock; /* initially lock = 1 */
down(lock)
Critical section
up(lock)
Yes
Does it satisfy deadlock-freedom? Yes
Does it satisfy starvation-freedom? Depends…
Does the algorithm satisfy mutex?
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
8
Semaphore as a General Synchronization Tool
Execute B in Pjj only after A executed in Pii
 Use semaphore flag initialized to 0
 Code:

Pii
…
time
A
up(flag)
0
Pjj
…
down(flag)
B
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
9
More on synchronization using semaphores
Three processes p1; p2; p3
semaphores
p1
down(s1);
A
up(s2);
s1 = 1, s2 = 0;
p2
down(s2);
B
up(s2);
p3
down(s2);
C
up(s1);
Which execution orders of A, B, C, are possible?
(A B* C)*
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
10
No guarantee for correct synchronization
P0
P1
down(S);
down(Q);
move1
up(S);
up(Q)
down(Q);
down(S);
move2
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
11
Negative-valued semaphores
Two atomic operations are supported by a semaphore S:
down(S)


S-If S<0 the process is blocked. It
will resume execution only when
S is non-negative
up(S)
 S++
 If there are blocked
processes (i.e. S≤0), wake-up
one of them
-3
 If S is negative, then there are –S blocked processes
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
12
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
13
Implementing a spin-lock with TSL

In user space, one can use TSL (test-set-lock)
mutex_lock:
TSL
CMP
JZE
CALL
JMP
ok:
RET
REG, mutex
REG, #0
ok
thread_yield
mutex_lock
mutex_unlock:
MOV
mutex, #0
RET
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
14
Implementing a negative semaphore with TSL
type semaphore = record
value, flag: integer;
L: list of process;
end;
down(S):
repeat until test-and-set(S.flag)
S.value--;
if (S.value < 0) {
add this process to S.L;
S.flag=0
sleep;
}
else S.flag=0
-3
L
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
15
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 1st place?
Busy-waiting is now guaranteed to be very short
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
16
Producer-Consumer Problem
buffer
in
out
 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
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
17
Bounded Buffer
buffer
0
1
2 item1
3 item2
2
Out
4 item3
producer
consumer
5 item4
6
In
7
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
18
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
19
Producer-Consumer implementation with semaphores
#define N
typedef int
semaphore
semaphore
semaphore
100
semaphore;
mutex = 1;
empty = N;
full = 0;
/* Buffer size */
/* access control to critical section */
/* counts empty buffer slots */
/* 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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
20
Producer-Consumer implementation with semaphores
void consumer(void)
{
int
item;
while(TRUE)
{
down(&full);
down(&mutex);
remove_item(&item);
up(&mutex);
up(&empty);
consume_item(item);
}
/* decrement count of full */
/* enter critical section */
/* take item from buffer) */
/* leave critical section */
/* update count of empty */
/* do something... */
}
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
21
Outline
 Semaphores and the producer/consumer problem
 Counting semaphores from binary semaphores
 Event counters and message passing synchronization
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
22
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
23
Implementing a counting semaphore with binary
semaphores (user space): take 1
binary-semaphore S1 initially 1, S2 initially 0, S.value initially 1
down(S):
down(S1);
S.value--;
if(S.value < 0){
L1: up(S1);
L2: down(S2); }
else up(S1);
up(S):
down(S1);
S.value++;
if(S.value ≤ 0)
up(S2);
up(S1)
This code does not work. Why?
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
24
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.
There is a discrepancy between the value of S and the
number of processes waiting on it
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
25
Implementing a counting semaphore with binary
semaphores (user space): take 2
binary-semaphore S1 initially 1, S2 initially 0, S.value initially 1
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?
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
26
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: an up(), a down(), an up()…
The critical section that protects the counter is entered
alternately by a producer or a consumer
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
27
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);
}
}
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
28
A Problematic Scheduling Scenario
Consider a Bounded buffer of 5 slots.
Assume there are 6 processes each filling five slots
in turn.
1
2
3
4
5
6
Empty.Value = 5
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
29
A Problematic Scheduling Scenario
1. five slots are filled by the first producer
1
2
3
4
5
6
Empty.Value = 0
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
30
A Problematic Scheduling Scenario
1. The second producer is blocked
1
2
3
4
5
6
Empty.Value = -1
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
31
A Problematic Scheduling Scenario
1. The third producer is blocked
1
2
3
4
5
6
Empty.Value = -2
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
32
A Problematic Scheduling Scenario
1. The fourth producer is blocked
1
2
3
4
5
6
Empty.Value = -3
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
33
A Problematic Scheduling Scenario
1. The fifth producer is blocked
1
2
3
4
5
6
Empty.Value = -4
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
34
A Problematic Scheduling Scenario
2. All blocked producers are waiting on S2
1
2
3
4
5
6
Empty.Value = -5
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
35
A Problematic Scheduling Scenario
3. The consumer consumes an item and is blocked
on Empty.S1 until a producer adds an item.
1
2
3
4
5
6
Empty.Value = -5
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
36
A Problematic Scheduling Scenario
3. The consumer consumes an item and is blocked
on S1 , one producer adds an item.
1
2
3
4
5
6
Empty.Value = -4
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
37
A Problematic Scheduling Scenario
4. Consumer must consume, only then another
producer wakes up and produces an item
1
2
3
4
5
6
Empty.Value = -3
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
38
A Problematic Scheduling Scenario
4. Same as in step 3.
1
2
3
4
5
6
Empty.Value = -2
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
39
A Problematic Scheduling Scenario
5. And again…
1
2
3
4
5
6
Empty.Value = -1
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
40
Implementing a counting semaphore with binary
semaphores (user space): take 3 (P.A. Kearns, 1988)
binary-semaphore S1=1, S2=0, value initially 1, integer wake=0
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);
Does THIS work?
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
41
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
42
Kearns' algorithm is wrong
 Processes P0..P7 perform down(S), P0 goes through, P1..P7 are preempted just
after 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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
43
Implementing a counting semaphore with binary
semaphores (user space): take 4 (Hemmendinger, 1989)
binary-semaphore S1=1, S2=0, integer wake=0
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);
This works
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
44
Implementing a counting semaphore with binary
semaphores (user space): take 5 (Barz, 1983)
binary-semaphore S1=1, S2=min(1, init_value), value=init_value
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);
This works, is simpler, and was published
earlier(!)…
Can we switch the order of downs in down(S)?
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
45
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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
46
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…
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
47
Outline
 Semaphores and the producer/consumer problem
 Counting semaphores from binary semaphores
 Event counters and message passing synchronization
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
48
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
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
49
producer-consumer with Event Counters
(for a single producer and a single consumer)
#define
typedef
event_counter
event_counter
N
int
in = 0;
out = 0;
100
event_counter;
/* counts inserted items */
/* 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, 2014, Meni Adler, Danny Hendler & Amnon Meisels
50
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);
}
}
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
51
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...
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
52
Producer-consumer with Message Passing
#define N
#define MSIZE
100
4
typedef int
message(MSIZE);
void producer(void)
{
int
item;
message
m;
while(TRUE) {
produce_item(&item);
receive(consumer, &m);
construct_message(&m, item);
send(consumer, &m);
}
/* message size */
/* message buffer */
/*wait for an empty */
/* send item */
}
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
53
Message passing (cont.)
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);
extract_item(&m, &item);
send(producer, &m);
consume_item(item);
}
}
/* get message with item */
/* send an empty reply */
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
54
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
Operating Systems, 2014, Meni Adler, Danny Hendler & Amnon Meisels
55
Download