To lower the overhead a more elaborate locking protocol test and test-and-set is used. The main idea is not to spin in test-and-set but increase the likelihood of successful test-and-set by using following entry protocol to the lock:
boolean locked := false // shared lock variable
procedure EnterCritical() {
do {
while (locked == true) skip // spin until lock seems'' free} while TestAndSet(locked) // actual atomic locking
}
Exit protocol is:
procedure ExitCritical() {
locked := false
}
The entry protocol uses normal memory reads to spin, waiting for the lock to become free. Test-and-set is only used to try to get the lock when normal memory read says it's free. Thus the expensive atomic memory operations happens less often than in simple spin around test-and-set.
If the programming language used supports short-circuit evaluation, the entry protocol could be implemented as:
procedure EnterCritical() {
while (locked == true or TestAndSet(locked) == true )
skip // spin until locked}