The solution is a combined approach. Each process gets its own lock variable, and a variable 'turn' is used to arbitrate in case of conflicts. The procedure for entering a critical region now becomes:
public class Mutex {(I've rewritten it a bit, to make it clearer what is going on, but the logic is exactly the same as that shown in the book.)
boolean interested[2]; // Whether each process wants to enter its critical region.
int turn; // In case of conflict, whose turn is it?void enterCriticalSection(int thisProcess){
int otherProcess = 1 - thisProcess;
interested[thisProcess] = true;
turn = otherProcess; // No, please, after you.
while(interested[otherProcess] && turn != thisProcess){
/* busywait */
}
}void leaveCriticalSection(int thisProcess){
interested[thisProcess] = false;
}
}
Note that the 'enterCriticalSection' procedure sets turn to 'otherProcess' before busywaiting. Isn't that a bit silly? Well, no. It's to ensure fairness. It is not silly, because if process #1 comes along while process #0 is in its critical section, process #1 sets 'turn' to 0 and waits politely. It is fair because it means that if two processes call 'enterCriticalSection' at about the same time, the last one to set 'turn' is the one which waits. Think about it.