Locks: OS Support: 21.1 A Simple Approach: Just Yield, Baby
Locks: OS Support: 21.1 A Simple Approach: Just Yield, Baby
Locks: OS Support
1
2 L OCKS : OS S UPPORT
void init() {
flag = 0;
}
void lock() {
while (TestAndSet(&flag, 1) == 1)
yield(); // give up the CPU
}
void unlock() {
flag = 0;
}
the CPU, and thus the other thread will run and finish its critical
section. In this simple case, the yielding approach works well.
Let us now consider the case where there are many threads
(say 100) contending for a lock repeatedly. In this case, if one
thread acquires the lock and is preempted before releasing it,
the other 99 will each call lock(), find the lock held, and yield the
CPU. Assuming some kind of round-robin scheduler, each of
the 99 will execute this run-and-yield pattern before the thread
holding the lock gets to run again. While better than our spin-
ning approach (which would waste 99 time slices spinning), this
approach is still costly; the cost of a context switch can be sub-
stantial, and there is thus plenty of waste.
Worse, we have not tackled the starvation problem at all.
A thread may get caught in an endless yield loop while other
threads repeatedly enter and exit the critical section. We clearly
will need an approach that addresses this problem directly.
O PERATING
S YSTEMS A RPACI -D USSEAU
L OCKS : OS S UPPORT 3
W HAT
A RPACI -D USSEAU H APPENS
W HEN
4 L OCKS : OS S UPPORT
not get set back to 0 when when another thread gets woken up.
Why is this? Well, it is not an error, but rather a necessity! When
a thread is woken up, it will be as if it is returning from park();
however, it does not hold the guard at that point in the code and
thus cannot even try to set the flag to 1. Thus, we just pass the
lock directly from the thread releasing the lock to the next thread
O PERATING
S YSTEMS A RPACI -D USSEAU
L OCKS : OS S UPPORT 5
queue_add(m->q, gettid());
setpark(); // new code
m->guard = 0;
W HAT
A RPACI -D USSEAU H APPENS
W HEN
6 L OCKS : OS S UPPORT
/* We have to wait now. First make sure the futex value we are
monitoring is truly negative (i.e. locked). */
v = *mutex;
if (v >= 0)
continue;
futex_wait (mutex, v);
}
}
/* There are other threads waiting for this mutex, wake one of them up.
futex_wake (mutex);
O PERATING
S YSTEMS A RPACI -D USSEAU
L OCKS : OS S UPPORT 7
21.4 Summary
The above approach shows how real locks are built these
days: some hardware support (in the form of a more power-
ful instruction) plus some operating system support (e.g., in the
form of park() and unpark() primitives). Of course, the de-
tails differ, and the exact code to perform such locking is usually
highly tuned. Check out the Solaris or Linux open source code
bases if you want to see more details; they are a fascinating read
[L09, S09].
W HAT
A RPACI -D USSEAU H APPENS
W HEN
8 L OCKS : OS S UPPORT
References
[D91] “Just Win, Baby: Al Davis and His Raiders”
Glenn Dickey, Harcourt 1991
There is even an undoubtedly bad book about Al Davis and his famous “just win” quote.
Or, I guess, the book is more about Al Davis and the Raiders, and maybe not just the quote.
Read the book to find out?
O PERATING
S YSTEMS A RPACI -D USSEAU