Any deadlock-free Lock algorithm requires allocating and then reading or writing at least n distinct locations in the worst case. This result motivates us to add to our multiprocessor machines,synchronization operations stronger than read-write, and use them as the basis of our mutual exclusion algorithms.
In this section, we observe why this linear bound isherent. The proof requries us to argue about the state of all memory used by a given multithreaded program. I list them as below.
Object's state => the state of its fields Thread's local state => the state of program counters and local variables Global state or system state => state of all objects and local states of the threads |
Definition 2.8.1. incosistent
For some global state S = (Sthreads, Slock) which shows that some thread is in the critical section, if the lock object state Slock is compatible with another global state S' = (S'threads, S'lock) in which no thread is in the critical section or is trying to enter the critical section, then we say Slock is in consistent.
Lemma 2.8.1. No deadlock-free Lock algorithm can enter an incosistent state.
For s and s', if thread B tries to enter the critical section, B cannot determine whether A is in the critical section through reading lock object state.
Definition 2.8.2. covering state
A covering state Scover for a lock object is one in which satisfies that
- There is at least one thread about to write to each shared location, but
- The lock object's locations "look" like the CS is empty.
Notice that A is poised to write LA, that is, the writing action will be done by A once A continues to run. Armong lock object's locations, which is LA or LB, depends on th real running.
How to maneuver threads A and B into a covering state?
Assuming that the initial lock object state S0 shows that "Empty Critical Section".
Step 1. Since the lock algorithm is deadlock-free, both thread A and B can enter the CS successfully. Consider an execution in which B runs through the CS 3times. Each time around, it must write some location, so consider the first location it writes when trying to enter the CS. Since there are only two locations, B must write one location twice. Call that location LB.
Let B run until it is poised to write location LB. Then we know the lock object's state is the same with S0[lock], since B has not written the lock object's locations yet.
Step 2. If A runs now, A will enter the CS.
If A writes only LB, then
Let A enter the CS, and write LB. Then let B write to LB, which will obliterate A's last write. The result is an inconsistent state: B cannot tell whether A is in the critical section.
Denote the location that A first write (except for LB) as LA. Let A run until it is poised to write LA. Let B run, obliterating any value A might have written to LB, entering and leaving the CS at most 3 times, and halting just before its second write to LB.
In this state, A is about to write LA, B is about to write LB, and the locations are consistent with no thread trying to enter or in the CS, as required in a covering state.
The procedure can be depicted as the following diagram.
REFERENCE: Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming