semaphores

advertisement
Synchronization 2: semaphores
and more…
1
Operating Systems, 2011, 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
 Wastes CPU time
 May cause priority inversion and deadlock
Operating Systems, 2011, 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, 2011, 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, 2011, Danny Hendler & Amnon Meisels
4
Synchronization Constructs – Semaphores (Dijkstra ‘68)
Two operations define a semaphore S:
DOWN(S)
p(s)
while(s <= 0);
s = s - 1;
UP(S)
s = s + 1;
v(s)
 Operations on the counter are performed indivisibly
S
is non-negative
 but this description busy-waits…
Operating Systems, 2011, Danny Hendler & Amnon Meisels
5
Semaphores (Dijkstra ‘68)
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 when
awakened by an up(S) operation
S--
up(S) [the `v’ operation]
 S++
 If there are blocked
processes, wake-up one of
them
 S is non-negative
 What exactly does “atomic” mean ??
Operating Systems, 2011, Danny Hendler & Amnon Meisels
6
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
A single up() operation for 2 down()s
Operating Systems, 2011, Danny Hendler & Amnon Meisels
7
Semaphores
(Dijkstra ‘68)
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 when
awakened by an up(S) operation
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, 2011, Danny Hendler & Amnon Meisels
8
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, 2011, Danny Hendler & Amnon Meisels
9
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, 2011, Danny Hendler & Amnon Meisels
10
Synchronization with 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 orderings of A, B, C, are possible?
(A B* C)*
Operating Systems, 2011, Danny Hendler & Amnon Meisels
11
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, 2011, Danny Hendler & Amnon Meisels
12
Negative-valued semaphores
Two atomic operations are supported by a semaphore S:
up(S)
down(S)


S-If S<0 the process is blocked. It
will resume execution only when
S is non-negative
 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, 2011, Danny Hendler & Amnon Meisels
13
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
14
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, 2011, Danny Hendler & Amnon Meisels
15
Bounded Buffer
buffer
0
1
2 item1
3 item2
2
Out
4 item3
producer
consumer
5 item4
6
In
7
Operating Systems, 2011, Danny Hendler & Amnon Meisels
16
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
17
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);
down(&empty);
down(&mutex);
enter_item(item);
up(&mutex);
up(&full);
}
}
/* generate something... */
/* decrement count of empty */
/* enter critical section */
/* insert into buffer */
/* leave critical section */
/* increment count of full slots */
Operating Systems, 2011, Danny Hendler & Amnon Meisels
18
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
19
Implementing a binary semaphore 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
| the equivalent of enter_region
mutex_unlock:
MOV
mutex, #0
RET
also called a Spin-lock
Operating Systems, 2011, Danny Hendler & Amnon Meisels
20
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
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
21
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
22
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
23
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)
24
Operating Systems, 2011, Danny Hendler & Amnon Meisels
24
Implementing a counting semaphore with
binary semaphores: take 1
binary-semaphore S1, S2 initially 1; S.value initially 1
down(S):
down(S1);
S.value--;
if(S.value < 0){
up(S1); // L1
down(S2); } //L2
else up(S1);
up(S):
down(S1);
S.value++;
if(S.value ≤ 0)
up(S2);
up(S1)
This code does not work
25
Operating Systems, 2011, Danny Hendler & Amnon Meisels
25
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
26
Operating Systems, 2011, Danny Hendler & Amnon Meisels
26
Implementing a counting semaphore with binary
semaphores: take 2
binary-semaphore S1=1, S2=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?
27
Operating Systems, 2011, Danny Hendler & Amnon Meisels
27
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
28
Operating Systems, 2011, Danny Hendler & Amnon Meisels
28
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);
}
}
29
void consumer(void)
{
int
item;
while(TRUE)
{
down(&full);
down(&mutex);
remove_item(&item);
up(&mutex);
up(&empty);
consume_item(item);
}
}
Operating Systems, 2011, Danny Hendler & Amnon Meisels
29
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
30
Empty.Value = 5
Operating Systems, 2011, Danny Hendler & Amnon Meisels
30
A Problematic Scheduling Scenario
1. five slots are filled by the first producer
1
2
3
4
5
6
31
Empty.Value = 0
Operating Systems, 2011, Danny Hendler & Amnon Meisels
31
A Problematic Scheduling Scenario
1. The second producer is blocked
1
2
3
4
5
6
32
Empty.Value = -1
Operating Systems, 2011, Danny Hendler & Amnon Meisels
32
A Problematic Scheduling Scenario
1. The third producer is blocked
1
2
3
4
5
6
33
Empty.Value = -2
Operating Systems, 2011, Danny Hendler & Amnon Meisels
33
A Problematic Scheduling Scenario
1. The fourth producer is blocked
1
2
3
4
5
6
34
Empty.Value = -3
Operating Systems, 2011, Danny Hendler & Amnon Meisels
34
A Problematic Scheduling Scenario
1. The fifth producer is blocked
1
2
3
4
5
6
35
Empty.Value = -4
Operating Systems, 2011, Danny Hendler & Amnon Meisels
35
A Problematic Scheduling Scenario
2. All blocked producers are waiting on S2
1
2
3
4
5
6
36
Empty.Value = -5
Operating Systems, 2011, Danny Hendler & Amnon Meisels
36
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
37
Empty.Value = -5
Operating Systems, 2011, Danny Hendler & Amnon Meisels
37
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
38
Empty.Value = -4
Operating Systems, 2011, Danny Hendler & Amnon Meisels
38
A Problematic Scheduling Scenario
4. Consumer must consume, only then another
producer wakes up and produces an item
1
2
3
4
5
6
39
Empty.Value = -3
Operating Systems, 2011, Danny Hendler & Amnon Meisels
39
A Problematic Scheduling Scenario
4. Same as in step 3.
1
2
3
4
5
6
40
Empty.Value = -2
Operating Systems, 2011, Danny Hendler & Amnon Meisels
40
A Problematic Scheduling Scenario
5. And again…
1
2
3
4
5
6
41
Empty.Value = -1
Operating Systems, 2011, Danny Hendler & Amnon Meisels
41
Implementing a counting semaphore with binary
semaphores: 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--; //L3
if(S.wake > 0) then
up(S2);} //L3
up(S1);
42
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
42
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
43
Operating Systems, 2011, Danny Hendler & Amnon Meisels
43
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)
44
Operating Systems, 2011, Danny Hendler & Amnon Meisels
44
Implementing a counting semaphore with binary
semaphores: take 4
(Hemmendinger, 1989)
binary-semaphore S1=1, S2=0, integer value =1, 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);
45
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
45
Implementing a counting semaphore with binary
semaphores: 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)?
46
Operating Systems, 2011, Danny Hendler & Amnon Meisels
46
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'
47
Operating Systems, 2011, Danny Hendler & Amnon Meisels
47
Fairness of semaphores
 Order of releasing blocked processes:
o Fair
o Processes are not allowed multiple entries if others are
waiting
 Another option:
o Open competition each time the lock is free
o Imitating the Java ‘wait’ ‘notify’ mechanism
o Starvation is possible
48
Operating Systems, 2011, Danny Hendler & Amnon Meisels
48
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);
49
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
49
Outline
 Semaphores and the producer/consumer problem
 Counting semaphores from binary semaphores
 Event counters and message passing synchronization
50
Operating Systems, 2011, Danny Hendler & Amnon Meisels
50
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
51
Operating Systems, 2011, Danny Hendler & Amnon Meisels
51
producer-consumer with Event Counters
#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 */
}
}
52
Operating Systems, 2011, Danny Hendler & Amnon Meisels
52
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);
}
}
53
Operating Systems, 2011, Danny Hendler & Amnon Meisels
53
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...
54
Operating Systems, 2011, Danny Hendler & Amnon Meisels
54
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 */
}
55
Operating Systems, 2011, Danny Hendler & Amnon Meisels
55
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);
}
}
56
/* get message with item */
/* send an empty reply */
Operating Systems, 2011, Danny Hendler & Amnon Meisels
56
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
57
Operating Systems, 2011, Danny Hendler & Amnon Meisels
57
Download