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:
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;