Mutual Exclusion
Mutual exclusion is the requirement that when one process is in a Critical Section that accesses shared resources, no other process may be in a critical section that accesses any of those shared resources.
Also see mutex.
Mutual exclusion methods include:
Buhr's 5 rules — CS343 §5.16 Mutual Exclusion Game
The “game” is writing an entry/exit protocol that holds against an adversarial scheduler. Rule 2 bounds what the adversary is allowed to do; the other four are what your protocol must provide despite it.
- Safety, only one thread can be in a critical section at a time with respect to a particular object
- Arbitrary scheduling assumption, threads may run at arbitrary speed and in arbitrary order, while the underlying system guarantees a thread makes progress
- No blocking from outside, a thread not in the entry/exit code may not prevent other threads from entering
- Selection cannot be postponed indefinitely, breaking this is indefinite postponement / livelock
- After a thread starts entry, it must eventually enter, breaking this is starvation
This is what every
breaks rule Nreference in the CS343 notes points to.
How to implement?
This part talks about how we generally implement a mutual exclusion mechanism. Though I think in practice, these aren’t used??
From a software perspective:
From a hardware perspective:
- Interrupt Disabling
- Use hardware instructions (i.e. test_and_set) to realize mutual exclusion and introduce a little bit of busy waiting. Everybody does this in practice.
Advantages of using a hardware implementation
- Applicable to any number of processes on either a single processor or multiple processors sharing main memory
- It is simple and therefore easy to verify
- It can be used to support multiple critical sections
Disadvantages of using a hardware implementation
- Busy-waiting consumes processor time
- Starvation is possible when a process leaves a critical section and more than one process is waiting.
- Deadlock with two resources and two processes, each process holding one resource
- Priority inversion
- If a low priority process has the critical region and a higher priority process needs, the higher priority process will obtain the processor to wait for the critical region
- Pipeline stalls
Because of the drawbacks of both the software and hardware solutions, we need to look for other mechanisms → Semaphore.
Using Compare-and-Swap Instruction
/* program mutualexclusion */
const int n = /* number of processes */;
int bolt;
void P(int i) {
while (true) {
while (compare_and_swap(bolt, 0, 1) == 1) /* do nothing */;
/* critical section */;
bolt = 0;
/* remainder */;
}
}
void main() {
bolt = 0;
parbegin (P(1), P(2), ... ,P(n));
}The hardware compare and swap
int compare_and_swap (int *word, int testval, int newval) {
int oldval;
oldval = *word
if (oldval == testval) *word = newval;
return oldval;
}Using Exchange Instruction
The software
/* program mutualexclusion */
int const n = /* number of processes */;
int bolt;
void P(int i) {
while (true) {
int keyi = 1;
do exchange (&keyi, &bolt)
while (keyi != 0);
/* critical section */;
bolt = 0;
/* remainder */;
}
}
void main() {
bolt = 0;
parbegin (P(1), P(2), ..., P(n));
}Exchange (Hardware level, wouldn’t work in software)
void exchange (int *register, int *memory) {
int temp;
temp = *memory;
*memory = *register;
*register = temp;
}