Outline • Announcements • Basic Synchronization Principles – continued – Semaphores

advertisement
Outline
• Announcements
• Basic Synchronization Principles – continued
– Semaphores
– Bounded-buffer problem
– Read-writer’s problem
Announcements
• The second quiz will be at the end of today’s
class
– It will be closed-book and closed-note
– It requires to compute average wait time and
turnaround time (or something like that) and you
need a calculator
• Questions regarding grading of homework and
programming assignments
– Please talk to Yong Chen first to resolve the issues
you have
– Come to me if the issues cannot be resolved
5/29/2016
COP4610
2
Announcements – cont.
• Demonstration of Lab 1
– Please sign up to demonstrate your program if
you have not done so
– You need to demo your program in LOV 105 D
at Yong Chen’s office
– You have to demonstrate your program on or
before Oct. 28, 2003
5/29/2016
COP4610
3
Interacting Processes - review
• Independent process
– Cannot affect or be affected by the other
processes in the system
– Does not share any data with other processes
• Interacting process
– Can affect or be affected by the other processes
– Shares data with other processes
– We focus on interacting processes through
physically or logically shared memory
5/29/2016
COP4610
4
Bounded-Buffer – review
5/29/2016
COP4610
5
Bounded-Buffer - cont.
• Suppose we have one producer and one
consumer, the variable counter is 5
– Producer: counter = counter +1
P1: load counter, r1
P2: add r1, #1, r2
P3: store r2, counter
– Consumer: counter = counter - 1
C1: load counter, r1
C2: add r1, #-1, r2
C3: store r2, counter
5/29/2016
COP4610
6
Bounded-Buffer - cont.
• A particular execution sequence
– P1: load counter, r1
– P2: add r1, #1, r2
--- Context switch ---– C1: load counter, r1
– C2: add r1, #-1, r2
– C3: store r2, counter
--- Context switch ---– P3: store r2, counter
– What is the value of counter?
5/29/2016
COP4610
7
Bounded-Buffer - cont.
• A particular execution sequence
– C1: load counter, r1
– C2: add r1, #-1, r2
--- Context switch ---– P1: load counter, r1
– P2: add r1, #1, r2
– P3: store r2, counter
--- Context switch ---– C3: store r2, counter
– What is the value of counter this time?
5/29/2016
COP4610
8
Bounded-Buffer - cont.
• A particular execution sequence
– C1: load counter, r1
– C2: add r1, #-1, r2
– C3: store r2, counter
--- Context switch ---– P1: load counter, r1
– P2: add r1, #1, r2
– P3: store r2, counter
--- Context switch ---– What is the value of counter this time?
5/29/2016
COP4610
9
Race Condition
• Race condition
– When several processes access and manipulate
the same data concurrently, there is a race among
the processes
– The outcome of the execution depends on the
particular order in which the access takes place
– This is called a race condition
5/29/2016
COP4610
10
Traffic Intersections
5/29/2016
COP4610
11
A Semaphore
5/29/2016
COP4610
12
The Critical-Section Problem
• n processes all competing to use some shared
data
• Each process has code segments, called
critical section, in which the shared data is
accessed.
• Problem – ensure that when one process is
executing in its critical section, no other
process is allowed to execute in its critical
section, called mutual exclusion
5/29/2016
COP4610
13
The Critical-Section Problem – cont.
• Structure of process Pi
repeat
entry section
critical section
exit section
reminder section
until false;
5/29/2016
COP4610
14
Requirements for Critical-Section Solutions
• Mutual Exclusion.
– If process Pi is executing in its critical section, then no
other processes can be executing in their critical sections.
• Progress
– If no process is executing in its critical section and there
exist some processes that wish to enter their critical
section, then the selection of the processes that will enter
the critical section next cannot be postponed indefinitely.
• Bounded Waiting
– A bound must exist on the number of times that other
processes are allowed to enter their critical sections after
a process has made a request to enter its critical section
and before that request is granted.
5/29/2016
COP4610
15
Solution through Disabling Interrupts
• In a uni-processor system, an interrupt causes
the race condition
– The scheduler can be called in the interrupt
handler, resulting in context switch and data
inconsistency
5/29/2016
COP4610
16
Solution through Disabling Interrupts – cont.
• Process Pi
repeat
disableInterrupts(); //entry section
critical section
enableInterrupts(); //exit section
reminder section
until false;
5/29/2016
COP4610
17
Solution through Disabling Interrupts – cont.
5/29/2016
COP4610
18
Solution through Disabling Interrupts – cont.
• This solution may affect the behavior of the I/O
system
– Interrupts can be disabled for an arbitrarily long time
• The interrupts can be disabled permanently if the program
contains an infinite loop in its critical section
– User programs are not allowed to enable and disable
interrupts directly
• However, if the operating system can provide system calls,
a user can use the system calls for synchronization
– Called semaphores and related system calls
5/29/2016
COP4610
19
Software Attempt to Solve the Problem
• Only 2 processes, P1 and P2
• General structure of process Pi (other process Pj)
repeat
entry section
critical section
exit section
reminder section
until false;
• Processes may share some common variables to
synchronize their actions.
5/29/2016
COP4610
20
Algorithm 1
• Shared variables:
– var turn: (0..1);
initially turn = 0
– turn - i  Pi can enter its critical section
• Process Pi
repeat
while turn  i do no-op;
critical section
turn := j;
reminder section
until false;
• Satisfies mutual exclusion, but not progress
5/29/2016
COP4610
21
Algorithm 2
• Shared variables
– var flag: array [0..1] of boolean;
initially flag [0] = flag [1] = false.
– flag [i] = true  Pi ready to enter its critical section
• Process Pi
repeat
flag[i] := true;
while flag[j] do no-op;
critical section
flag [i] := false;
remainder section
until false;
• Satisfies mutual exclusion, but not progress requirement.
5/29/2016
COP4610
22
Algorithm 2 – version 1
• Shared variables
– var flag: array [0..1] of boolean;
initially flag [0] = flag [1] = false.
– flag [i] = true  Pi ready to enter its critical section
• Process Pi
repeat
while flag[j] do no-op;
flag[i] := true;
critical section
flag [i] := false;
remainder section
until false;
• Does not satisfy mutual exclusion
5/29/2016
COP4610
23
Algorithm 3
• Combined shared variables of algorithms 1 and 2.
• Process Pi
repeat
flag [i] := true;
turn := j;
while (flag [j] and turn = j) do no-op;
critical section
flag [i] := false;
remainder section
until false;
• Meets all three requirements; solves the critical-section problem
for two processes.
5/29/2016
COP4610
24
Bakery Algorithm
Critical section for n processes
• Before entering its critical section, process receives
a number. Holder of the smallest number enters the
critical section.
• If processes Pi and Pj receive the same number, if i
< j, then Pi is served first; else Pj is served first.
• The numbering scheme always generates numbers
in increasing order of enumeration; i.e.,
1,2,3,3,3,3,4,5...
5/29/2016
COP4610
25
Bakery Algorithm – cont.
• Notation < lexicographical order (ticket #, process
id #)
– (a,b) < c,d) if a < c or if a = c and b < d
– max (a0,…, an-1) is a number, k, such that k  ai for i - 0,
…, n – 1
• Shared data
var choosing: array [0..n – 1] of boolean;
number: array [0..n – 1] of integer,
Data structures are initialized to false and 0
respectively
5/29/2016
COP4610
26
Bakery Algorithm (Cont.)
repeat
choosing[i] := true;
number[i] := max(number[0], number[1], …, number [n – 1])+1;
choosing[i] := false;
for j := 0 to n – 1
do begin
while choosing[j] do no-op;
while number[j]  0
and (number[j],j) < (number[i], i) do no-op;
end;
critical section
number[i] := 0;
remainder section
until false;
5/29/2016
COP4610
27
Algorithm 4
• Shared variables:
– boolean lock;
initially lock = FALSE
– lock is FALSE  Pi can enter its critical section
• Process P1
Process P2
repeat
while (lock) do no-op;
lock = TRUE;
critical section
lock = FALSE;
reminder section
until false;
repeat
while (lock) do no-op;
lock = TRUE;
critical section
lock = FALSE
reminder section
until false;
5/29/2016
COP4610
28
Busy Wait Condition
shared boolean lock = FALSE;
shared double balance;
Code for p1
Code for p2
COP4610
Interrupt
lock = FALSE
Interrupt
Interrupt
5/29/2016
lock = TRUE
p2
p1
/* Acquire the lock */
while(lock) ;
lock = TRUE;
/* Execute critical sect */
balance = balance - amount;
/* Release lock */
lock = FALSE;
Blocked
at while
/* Acquire the lock */
while(lock) ;
lock = TRUE;
/* Execute critical sect */
balance = balance + amount;
/* Release lock */
lock = FALSE;
29
Synchronization Hardware
• Test and modify the content of a word atomically
(indivisibly)
– The procedure cannot be interrupted until it has completed the
routine
– Implemented as a test-and-set instruction
boolean Test-and-Set (boolean target)
{ boolean tmp
tmp = target;
target = true;
return tmp;
}
5/29/2016
COP4610
30
Test and Set Instruction – cont.
• TS(m): [Reg_i = memory[m]; memory[m] = TRUE;]
Data
CC
Register Register
R3
…
m
Data
CC
Register Register
…
R3
m
FALSE
Primary
Memory
(a) Before Executing TS
5/29/2016
FALSE
=0
TRUE
Primary
Memory
(b) After Executing TS
COP4610
31
Mutual Exclusion with Test-and-Set
• Shared data: boolean lock ;
– Initially false
• Process Pi
repeat
while Test-and-Set (lock) do no-op;
critical section
lock = false;
remainder section
until false;
5/29/2016
COP4610
32
Semaphores
• Semaphore S – integer variable
• can only be accessed via two indivisible
(atomic) operations
– As if they were a single machine instruction
wait (S): while S 0 do no-op;
S := S – 1;
signal (S): S := S + 1;
5/29/2016
COP4610
33
Two Types of Semaphores
• Counting semaphore – integer value can
range over an unrestricted domain.
• Binary semaphore – integer value can
range only between 0 and 1
– Can be simpler to implement.
• Can implement a counting semaphore S
using binary semaphores.
5/29/2016
COP4610
34
Example: Critical Section of n Processes
• Shared variables
– var mutex : semaphore
– initially mutex = 1
• Process Pi
repeat
wait(mutex);
critical section
signal(mutex);
remainder section
until false;
5/29/2016
COP4610
35
Shared Account Balance Problem
Proc_0() {
. . .
/* Enter the CS */
P(mutex);
balance += amount;
V(mutex);
. . .
}
proc_1() {
. . .
/* Enter the CS */
P(mutex);
balance -= amount;
V(mutex);
. . .
}
semaphore mutex = 1;
fork(proc_0, 0);
fork(proc_1, 0);
5/29/2016
COP4610
36
Sharing Two Variables
proc_A() {
while(TRUE) {
<compute section A1>;
update(x);
/* Signal proc_B */
V(s1);
<compute section A2>;
/* Wait for proc_B */
P(s2);
retrieve(y);
}
}
proc_B() {
while(TRUE) {
/* Wait for proc_A */
P(s1);
retrieve(x);
<compute section B1>;
update(y);
/* Signal proc_A */
V(s2);
<compute section B2>;
}
}
semaphore s1 = 0;
semaphore s2 = 0;
fork(proc_A, 0);
fork(proc_B, 0);
5/29/2016
COP4610
37
Bounded Buffer Problem
Empty Pool
Producer
Consumer
Full Pool
5/29/2016
COP4610
38
Bounded Buffer Problem – cont.
producer() {
consumer() {
buf_type *next, *here;
buf_type *next, *here;
while(TRUE) {
while(TRUE) {
produce_item(next);
/* Claim full buffer */
/* Claim an empty */
P(full);
P(empty);
P(mutex);
P(mutex);
here = obtain(full);
here = obtain(empty);
V(mutex);
V(mutex);
copy_buffer(here, next);
copy_buffer(next, here);
P(mutex);
P(mutex);
release(here, emptyPool);
release(here, fullPool);
V(mutex);
V(mutex);
/* Signal an empty buffer */
/* Signal a full buffer */
V(empty);
V(full);
consume_item(next);
}
}
}
}
semaphore mutex = 1;
semaphore full = 0;
/* A general (counting) semaphore */
semaphore empty = N;
/* A general (counting) semaphore */
buf_type buffer[N];
fork(producer, 0);
fork(consumer, 0);
5/29/2016
COP4610
39
Bounded Buffer Problem – cont.
producer() {
consumer() {
buf_type *next, *here;
buf_type *next, *here;
while(TRUE) {
while(TRUE) {
produce_item(next);
/* Claim full buffer */
/* Claim an empty */
P(full);
P(empty);
P(mutex);
P(mutex);
here = obtain(full);
here = obtain(empty);
V(mutex);
V(mutex);
copy_buffer(here, next);
copy_buffer(next, here);
P(mutex);
P(mutex);
release(here, emptyPool);
release(here, fullPool);
V(mutex);
V(mutex);
/* Signal an empty buffer */
/* Signal a full buffer */
V(empty);
V(full);
consume_item(next);
}
}
}
}
semaphore mutex = 1;
semaphore full = 0;
/* A general (counting) semaphore */
semaphore empty = N;
/* A general (counting) semaphore */
buf_type buffer[N];
fork(producer, 0);
fork(consumer, 0);
5/29/2016
COP4610
40
Bounded Buffer Problem – cont.
consumer() {
producer() {
buf_type *next, *here;
buf_type *next, *here;
while(TRUE) {
while(TRUE) {
/* Claim full buffer */
produce_item(next);
P(mutex);
/* Claim an empty */
P(full);
P(empty);
here = obtain(full);
P(mutex);
V(mutex);
here = obtain(empty);
copy_buffer(here, next);
V(mutex);
P(mutex);
copy_buffer(next, here);
release(here, emptyPool);
P(mutex);
V(mutex);
release(here, fullPool);
/* Signal an empty buffer */
V(mutex);
V(empty);
/* Signal a full buffer */
consume_item(next);
V(full);
}
}
}
}
semaphore mutex = 1;
semaphore full = 0;
/* A general (counting) semaphore */
semaphore empty = N;
/* A general (counting) semaphore */
buf_type buffer[N];
fork(producer, 0);
fork(consumer, 0);
5/29/2016
COP4610
41
Readers-Writers Problem
Writers
Readers
5/29/2016
COP4610
42
Readers-Writers Problem (2)
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Shared Resource
5/29/2016
COP4610
43
Readers-Writers Problem (3)
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Shared Resource
5/29/2016
COP4610
44
Readers-Writers Problem (4)
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Writer
Writer
Writer
Writer
Writer
Writer
Writer
Shared Resource
5/29/2016
COP4610
45
Readers-writers with active readers
5/29/2016
COP4610
46
First and Second Policy
5/29/2016
COP4610
47
First Solution
reader() {
writer() {
while(TRUE) {
while(TRUE) {
<other computing>;
<other computing>;
P(mutex);
P(writeBlock);
readCount++;
/* Critical section */
if(readCount == 1)
access(resource);
P(writeBlock);
V(writeBlock);
V(mutex);
}
/* Critical section */
}
access(resource);
P(mutex);
readCount--;
•First reader competes with writers
if(readCount == 0)
V(writeBlock);
•Last reader signals writers
V(mutex);
}
}
resourceType *resource;
int readCount = 0;
semaphore mutex = 1;
semaphore writeBlock = 1;
fork(reader, 0);
fork(writer, 0);
5/29/2016
COP4610
48
First Solution (2)
reader() {
while(TRUE) {
<other computing>;
P(mutex);
readCount++;
if(readCount == 1)
P(writeBlock);
V(mutex);
/* Critical section */
access(resource);
P(mutex);
readCount--;
if(readCount == 0)
V(writeBlock);
V(mutex);
}
}
resourceType *resource;
int readCount = 0;
semaphore mutex = 1;
semaphore writeBlock = 1;
fork(reader, 0);
fork(writer, 0);
5/29/2016
writer() {
while(TRUE) {
<other computing>;
P(writeBlock);
/* Critical section */
access(resource);
V(writeBlock);
}
}
•First reader competes with writers
•Last reader signals writers
•Any writer must wait for all readers
•Readers can starve writers
•“Updates” can be delayed forever
•May not be what we want
COP4610
49
Writer Precedence
reader() {
while(TRUE) {
<other computing>;
P(readBlock);
P(mutex1);
readCount++;
if(readCount == 1)
P(writeBlock);
V(mutex1);
V(readBlock);
4
2
access(resource);
P(mutex1);
readCount--;
if(readCount == 0)
V(writeBlock);
V(mutex1);
1
writer() {
while(TRUE) {
<other computing>;
P(mutex2);
writeCount++;
if(writeCount == 1)
P(readBlock);
3
V(mutex2);
P(writeBlock);
access(resource);
V(writeBlock);
P(mutex2)
writeCount--;
if(writeCount == 0)
V(readBlock);
V(mutex2);
}
}
}
}
int readCount = 0, writeCount = 0;
semaphore mutex = 1, mutex2 = 1;
semaphore readBlock = 1, writeBlock = 1, writePending = 1;
fork(reader, 0);
5/29/2016
COP4610
50
fork(writer, 0);
Writer Precedence (2)
reader() {
writer() {
while(TRUE) {
while(TRUE) {
<other computing>;
<other computing>;
P(mutex2);
4 P(writePending);
P(readBlock);
writeCount++;
P(mutex1);
if(writeCount == 1)
readCount++;
P(readBlock);
3
if(readCount == 1)
V(mutex2);
2
P(writeBlock);
P(writeBlock);
V(mutex1);
access(resource);
V(readBlock);
V(writeBlock);
V(writePending);
P(mutex2)
access(resource);
writeCount--;
1
P(mutex1);
if(writeCount == 0)
readCount--;
V(readBlock);
if(readCount == 0)
V(mutex2);
V(writeBlock);
}
V(mutex1);
}
}
}
int readCount = 0, writeCount = 0;
semaphore mutex = 1, mutex2 = 1;
semaphore readBlock = 1, writeBlock = 1, writePending = 1;
fork(reader, 0);
5/29/2016
COP4610
51
fork(writer, 0);
The Sleepy Barber
• Barber can cut one person’s hair at a time
• Other customers wait in a waiting room
Entrance to Waiting
Room (sliding door)
Shop Exit
Entrance to Barber’s
Room (sliding door)
Waiting Room
5/29/2016
COP4610
52
Sleepy Barber
customer() {
while(TRUE) {
customer = nextCustomer();
if(emptyChairs == 0)
continue;
P(chair);
P(mutex);
emptyChairs--;
takeChair(customer);
V(mutex);
V(waitingCustomer);
}
}
barber() {
while(TRUE) {
P(waitingCustomer);
P(mutex);
emptyChairs++;
takeCustomer();
V(mutex);
V(chair);
}
}
semaphore mutex = 1, chair = N, waitingCustomer = 0;
int emptyChairs = N;
fork(customer, 0);
fork(barber, 0);
5/29/2016
COP4610
53
Implementing Semaphores
• Minimize effect on the I/O system
• Processes are only blocked on their own
critical sections (not critical sections that they
should not care about)
• If disabling interrupts, be sure to bound the
time they are disabled
5/29/2016
COP4610
54
Implementing Semaphores Using Interrupts
class semaphore {
int value;
public:
semaphore(int v = 1) { value = v;};
P(){
disableInterrupts();
while(value == 0) {
enableInterrupts();
disableInterrupts();
}
value--;
enableInterrupts();
};
V(){
disableInterrupts();
value++;
enableInterrupts();
};
};
5/29/2016
COP4610
55
Using the TS Instruction
boolean s = FALSE;
. . .
while(TS(s)) ;
<critical section>
s = FALSE;
. . .
5/29/2016
semaphore s = 1;
. . .
P(s) ;
<critical section>
V(s);
. . .
COP4610
56
Implementing the General Semaphore
struct semaphore {
int value = <initial value>;
boolean mutex = FALSE;
boolean hold = TRUE;
};
shared struct semaphore s;
P(struct semaphore s) {
while(TS(s.mutex)) ;
s.value--;
if(s.value < 0) (
s.mutex = FALSE;
while(TS(s.hold)) ;
}
else
s.mutex = FALSE;
}
5/29/2016
V(struct semaphore s) {
while(TS(s.mutex)) ;
s.value++;
if(s.value <= 0) (
while(!s.hold) ;
s.hold = FALSE;
}
s.mutex = FALSE;
}
COP4610
57
Semaphore Implementation – cont.
• Semaphores implemented using interrupt
disabling and test-and-set require busy
waiting
– This type of semaphores is often called spinlock
5/29/2016
COP4610
58
Semaphore Implementation – cont.
• Define a semaphore as a structure
typedef struct {
int value;
queue L;
} semaphore;
• Assume two simple operations:
– block suspends the process that invokes it.
– wakeup(P) resumes the execution of a blocked
process P.
5/29/2016
COP4610
59
Semaphore Implementation - cont.
• Semaphore operations now defined as
P(S): S.value = S.value – 1;
if S.value < 0
then begin
add this process to S.L;
block;
end;
5/29/2016
COP4610
60
Semaphore Implementation - cont.
V(S):
S.value = S.value + 1;
if S.value  0
then begin
remove a process P from S.L;
wakeup(P);
end;
5/29/2016
COP4610
61
Semaphore Implementation - cont.
• Semaphores are resources in the above
implementation
5/29/2016
COP4610
62
Issues Using Semaphores
• Deadlock
– two or more processes are waiting indefinitely for an event
that can be caused by only one of the waiting processes.
• Let S and Q be two semaphores initialized to 1
P0
P(S);
P(Q);

V(S);
V(Q)
P1
P(Q);
P(S);

V(Q);
V(S);
• Starvation – indefinite blocking
– A process may never be removed from the semaphore queue
in which it is suspended.
5/29/2016
COP4610
63
Active and Passive Semaphores
• There is a subtle problem related to
semaphore implementation
– Bounded waiting may not be satisfied
• when the passive V operation is used where the
implementation increments the semaphore with no
opportunity for a context switch
5/29/2016
COP4610
64
Active vs. Passive Semaphores – cont.
• A process can dominate the semaphore
– Performs V operation, but continues to execute
– Performs another P operation before releasing the
CPU
– Called a passive implementation of V
5/29/2016
COP4610
65
Active and Passive Semaphores – cont.
5/29/2016
COP4610
66
Active and Passive Semaphores – cont.
• Active semaphores
– In contrast to passive semaphores, a yield or
similar procedure will be called after
incrementing the semaphore for a context switch
in a V operation implementation
• Changes semantics of semaphore!
– Cause people to rethink solutions
5/29/2016
COP4610
67
Summary
• Processes that share data need to be
synchronized
– Otherwise, a race condition may exist
• Semaphores are the basic mechanism
underlying synchronization and can be used
to solve different synchronization problems
– Critical section problem
– Bounded-buffer problem
– Readers-writers problem
5/29/2016
COP4610
68
Session Information
• COP 4610 / CGS 5765
–
–
–
–
–
Section
Section 6
Section 2
Section 3
Section 4
Recitation time
08:00-08:55 AM
09:05-09:55 AM
11:15AM -12:05 PM
12:20-1:10 PM
• For problem 3c., for round-robin scheduling,
we assume a newly arrived process will be
inserted at the end of the ready queue at the
time it arrives
5/29/2016
COP4610
69
5/29/2016
COP4610
70
Download