Information Technology Reference
In-Depth Information
1. Always synchronize with locks and condition variables.
Either locks and condition variables or semaphores could be used to im-
plement shared objects. We recommend that you be able to read and
understand semaphores so you can understand legacy code, but that you
only write new code using locks and condition variables.
99% of the time code with locks and condition variables is more clear than
the equivalent semaphore code because it is more \self-documenting". If
the code is well-structured, it is usually clear what each synchronization
action is doing. Admittedly, occasionally semaphores seem to fit what you
are doing perfectly because you can map the object's invariants onto the
internal state of the semaphore exactly|for example you can write an ex-
tremely concise version of our blocking bounded queue using semaphores|
but what happens when the code changes a bit next month? Will the fit
be as good? For consistency and simplicity, you should choose one of the
two styles and stick with it, and in our opinion, the right one to pick is to
use locks and condition variables.
2. Always acquire the lock at the beginning of a method and release
it right before the return.
This is mainly an extension of the principle of consistent structure: pick
one way of doing things and always follow it. The benefit here is that it is
easy to read code and see where the lock is held and where it isn't because
synchronization is structured on a method-by-method basis. Conversely,
if Lock::Acquire() and Lock::Release() calls are buried in the middle
of a method, it is harder to quickly inspect and understand the code.
Taking a step back, if there is a logical chunk of code that you can identify
as a set of actions that require a lock, then that section should probably
be its own procedure|it is a set of logically related actions. If you nd
yourself wanting to grab a lock in the middle of a procedure, that is
usually a red flag that you should break the piece you are considering
into a separate procedure. We are all sometimes lazy about creating new
procedures when we should. Take advantage of this signal, and you will
write clearer code.
3. Always hold the lock when operating on a condition variable.
The reason you signal on a condition variable because you just got done
manipulating shared state|some other thread is waiting in a loop for
some test on shared state become to true. Condition variables are use-
less without shared state and shared state should only be accessed while
holding a lock.
Many libraries enforce this rule|you cannot call any condition variable
methods unless you hold the corresponding lock. But some run-time sys-
tems and libraries allow sloppiness, so take care.
4. Always wait in a while() loop
Search WWH ::




Custom Search