Process Synchronization - Class
Process Synchronization - Class
Background
The Critical-Section Problem
Synchronization Hardware
Semaphores
Classical Problems of Synchronization
Critical Regions
Monitors
Message Passing
Synchronization in Solaris 2 & Windows 2000
inconsistency.
#define BUFFER_SIZE 10
typedef struct {
...
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int counter = 0;
item nextProduced;
while (1) {
; /* do nothing */
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;
Consumer process
item nextConsumed;
while (1) {
while (counter == 0)
; /* do nothing */
nextConsumed = buffer[out];
counter--;
The statements
counter++;
counter--;
register1 = counter
register1 = register1 + 1
counter = register1
register2 = counter
register2 = register2 – 1
counter = register2
interleaved.
The value of count may be either 4 or 6, where the correct result should be 5.
Race Condition
Each process has a code segment, called critical section, in which the shared data is accessed.
Each process must request permission to enter its critical section. The section of code
Problem – ensure that when one process is executing in its critical section, no other
some processes that wish to enter their critical section, then the
selection of the processes that will enter the critical section next
Shared variables:
int turn;
initially turn = 0
turn - i Pi can enter its critical section
Process Pi
do {
while (turn != i) ;
critical section
turn = j;
reminder section
} while (1);
Satisfies mutual exclusion, but not progress
turn P0 P1
0 CS while
1 RS CS
0 RS RS
0 RS while
Shared variables
boolean flag[2];
initially flag [0] = flag [1] = false.
flag [i] = true P ready to enter its critical section
i
Process P
i
do {
flag[i] := true;
while (flag[j]) ;
critical section
flag [i] = false;
remainder section
} while (1);
Satisfies mutual exclusion, but not progress requirement.
If flag[0] and flag[1] are both set to be true, both
processes are looping forever.
do {
choosing[i] = true;
number[i] = max(number[0], number[1], …, number [n – 1])+1;
choosing[i] = false;
for (j = 0; j < n; j++) {
while (choosing[j]) ;
while ((number[j] != 0) && ((number[j] < number[i]) ||
(number[j] == number[i] && j < i))) ;
}
critical section
number[i] = 0;
remainder section
} while (1);
Shared data:
boolean lock = false;
Process Pi
do {
while (TestAndSet(lock)) ;
critical section
lock = false;
remainder section
}
Process P
i
do {
key = true;
while (key == true)
Swap(lock,key);
critical section
lock = false;
remainder section
}
These two solutions in Figure 7.7 and Figure 7.9 don’t
satisfy the bounded-waiting requirement.
The algorithm in Figure 7.10 satisfies all the critical-
section requirement.
1. Disable interrupts.
2. Shared lock variable.
3. Strict alteration. See Ex6.c. See the manual entry for
shared memory allocation: man shmget and Ex6.c and
programs in shm directory.
4. Peterson's solution [1981]. Challenge: modify the code in
Ex6.c to implement Peterson's solution for 2 processes.
Note several variables are shared:
shared int turn = 0;
shared int flag[2] = {FALSE,FALSE};
5. Hardware solution: Test-and-Set Locks (TSL).
signal (S):
S++;
Note: These operations were originally termed P (wait, proberen)
and V (signal, verhogen). In order to distinguish with the C/UNIX
function wait and signal, in our programming examples we use
DOWN and UP to indicate wait and signal respectively.
Process Pi:
do {
wait(mutex);
critical section
signal(mutex);
remainder section
} while (1);
Data structures:
binary-semaphore S1, S2;
int C:
Initialization:
S1 = 1
S2 = 0
C = initial value of semaphore S
signal operation
wait(S1);
C ++;
if (C <= 0)
signal(S2);
else
signal(S1);
DOWN(mutex);
- critical section -
UP(mutex);
S1 S2
A ----> B ----> D
| ^
| S1 S3 |
+-----> C ------+
Process A:
----------
- do work of A
UP(S1); /* Let B or C start */
UP(S1); /* Let B or C start */
Process B:
----------
DOWN(S1); /* Block until A is finished */
- do work of B
UP(S2);
Process C:
----------
DOWN(S1);
- do work of C
UP(S3);
Process D:
----------
DOWN(S2);
DOWN(S3);
- do work of D
S1 S2
A ----> B ----> D
| ^
| S3 S4 |
+-----> C ------+
Process A:
----------
- do work of A
UP(S1); /* Let B start */
UP(S3); /* Let C start */
Process B:
----------
DOWN(S1); /* Block until A is finished */
- do work of B
UP(S2);
Process C:
----------
DOWN(S3);
- do work of C
UP(S4);
Process D:
----------
DOWN(S2);
DOWN(S4);
- do work of D
Bounded-Buffer Problem
Dining-Philosophers Problem
Shared data
Initially:
do {
…
produce an item in nextp
…
wait(not_full);
wait(mutex);
…
add nextp to buffer
…
signal(mutex);
signal(not_empty);
} while (1);
do {
wait(not_empty)
wait(mutex);
…
remove an item from buffer to nextc
…
signal(mutex);
signal(not_full);
…
consume the item in nextc
…
} while (1);
Initially
wait(wrt);
…
writing is performed
…
signal(wrt);
wait(mutex);
readcount++;
if (readcount == 1)
wait(rt);
signal(mutex);
…
reading is performed
…
wait(mutex);
readcount--;
if (readcount == 0)
signal(wrt);
signal(mutex):
Philosopher i:
do {
wait(chopstick[i])
wait(chopstick[(i+1) % 5])
…
eat
…
signal(chopstick[i]);
signal(chopstick[(i+1) % 5]);
…
think
…
} while (1);
Shared data:
struct buffer {
int pool[n];
int count, in, out;
}
monitor monitor-name
{
shared variable declarations
procedure body P1 (…) {
...
}
procedure body P2 (…) {
...
}
procedure body Pn (…) {
...
}
{
initialization code
}
}
void putdown(int i) {
state[i] = thinking;
// test left and right neighbors
test((i+4) % 5);
test((i+1) % 5);
}
Variables
semaphore mutex; // (initially = 1)
semaphore next; // (initially = 0)
int next-count = 0;
x-count++;
if (next-count > 0)
signal(next);
else
signal(mutex);
wait(x-sem);
x-count--;
if (x-count > 0) {
next-count++;
signal(x-sem);
wait(next);
next-count--;
}