On 09/18/12 18:24, Stefan Teleman wrote:
On Tue, Sep 18, 2012 at 4:35 PM, Liviu Nicoara <nikko...@hates.ms> wrote:
I will concede that I might be wrong and I am open to arguments. I would
accept as a counter-argument this program if you can show a runtime failure.
The the first read of the counter variable is outside a mutex lock
correct? The read is followed by a 0 comparison, correct?
Correct.
What guarantees that between the read and the comparison the value of
the counter variable hasn't been modified by another thread? The
thread currently doing the comparison cannot guarantee it: it hasn't
locked the mutex. Other threads may be running - actually they
probably are. Another thread may have already acquired the mutex and
incremented the value of counter. Your thread has no way of knowing if
that has happened, because it does not yet have exclusive access to
the counter variable. It will, after it acquires the mutex.
It does not matter if the value is changed concurrently in between the
reading of it and the actual comparison. The value can only be 0, in
which case it takes the branch that locks the mutex and the next read
will absolutely see a fresh value; or it can be 1 in which case it has
already been initialized and this thread does not pay the penalty of a
lock anymore.
Where is it reading the variable from? A register? Is it declared
volatile? L2 cache? L3 cache?
Irrelevant. If the value has not been changed it can be read from either
the cache or directly from the memory. If the value has been changed
concurrently in between the reading and the actual comparison, the
processor sees either a stale value of 0, or the new value 1. It is
guaranteed that any thread reading the value after the (one and only)
unlock will see a fresh value.
The program, as you wrote it, implicitly acknowledges that it is not
thread safe. That is the point of the double check: one before the
mutex lock, and one after it.
That is a misstatement of the program intentions. See below.
The point of the first check has nothing
to do with thread-safety, and everything to do with a minor
optimization: if the value stored in variable counter is already not
zero, then there's no point in locking the mutex or performing the
increment.
The first check is indeed an optimization. It is the point of this
exercise to show that the unguarded reads in the localization library
are not defects and the code, simplified in my test case, is thread safe
in exactly the respects I mentioned before: the program only observes
consistent, correct values (program states) in a concurrent environment.
HTH.
Liviu