Tom Kelliher, CS42
Sept. 27, 1996
Recall cooperating processes --- they affect or are affected by other processes through access to shared variables.
E.g., threads.
Producer/Consumer (again).
const int N = 10;
int in = 0, out = 0, count = 0;
data buffer[N];
producer()
{
data next;
while (1)
{
produce in next;
while (counter == n)
;
buffer[in] = next;
in = ++in % N;
++counter;
}
}
consumer()
{
data next;
while (1)
{
while (counter == 0)
;
next = buffer[out];
out = ++out % N;
--counter;
consume next;
}
}
What variables are being shared?
What is the nature of the sharing?
Critical variables; critical sections.
Cases where cooperating processes need not synchronize to share resources:
What does atomic mean?
Characteristics of ``trouble situations:''
The overlapping portion of each process, where the shared variables are being accessed.
Necessary and sufficient conditions for a solution to the c.s. problem:
is executing in one of its critical
sections, no
,
, is executing in its critical sections.
Assumptions:
(for n processes,
)
Pi:
do {
mutexbegin; /* CS entry */
CSi;
mutexend; /* CS exit */
non-CS
} while (!done);
mutexbegin()
{
disable_ints;
}
mutexend()
{
enable_ints;
}
Problems with this approach:
int TAS(int& val)
{
int temp;
temp = val; // Body performed atomically.
val = 1;
return temp;
}
int FAI(int& val)
{
return val++; // Performed atomically.
}
FAI solution to CS problem for n processes:
int nextTicket = 0, serving = 0;
mutexbegin()
{
int myTicket;
myTicket = FAI(nextTicket);
while (myTicket != serving)
;
}
mutexend()
{
++serving;
}
Correctness proof:
Assumption: no process ``plays'' with control variables.
Critical section code:
int turn = 0; /* shared control variable */ Pi: /* i is 0 or 1 */ while (turn != i) ; /* busy wait */ CSi; turn = 1 - i;
Remove strict alternation requirement
int flag[2] = { FALSE, FALSE } /* flag[i] indicates that Pi is in its */
/* critical section */
while (flag[1 - i])
;
flag[i] = TRUE;
CSi;
flag[i] = FALSE;
Restore mutual exclusion
int flag[2] = { FALSE, FALSE } /* flag[i] indicates that Pi wants to */
/* enter its critical section */
flag[i] = TRUE;
while (flag[1 - i])
;
CSi;
flag[i] = FALSE;
Attempt to remove the deadlock
int flag[2] = { FALSE, FALSE } /* flag[i] indicates that Pi wants to */
/* enter its critical section */
flag[i] = TRUE;
while (flag[1 - i]) {
flag[i] = FALSE;
delay; /* sleep for some time */
flag[i] = TRUE;
}
CSi;
flag[i] = FALSE;
int flag[2] = { FALSE, FALSE } /* flag[i] indicates that Pi wants to */
/* enter its critical section */
int turn = 0; /* turn indicates which process has */
/* priority in entering its critical */
/* section
flag[i] = TRUE;
turn = 1 - i;
while (flag[1 - i] && turn == 1 - i)
;
CSi;
flag[i] = FALSE;
Lamport's Bakery algorithm
int choosing[NPROCS] = { FALSE } /* cheating initializer */
int number[NPROCS] = { 0 }
choosing[i] = TRUE;
number[i] = max(number) + 1;
choosing[i] = FALSE;
for (j = 0; j < NPROCS; j++) {
while (choosing[j])
;
while (number[j] != 0 && (number[j] < number[i] ||
number[j] == number[i] && j < i) )
;
}
CSi;
number[i] = 0;