Helgrind: a thread error detector
• When a condition variable (CV) is signalled on by thread T1 and some other thread T2 is thereby released from a
wait on the same CV, then the memory accesses in T1 prior to the signalling must happen-before those in T2 after
it returns from the wait. If no thread was waiting on the CV then there is no effect.
• If instead T1 broadcasts on a CV, then all of the waiting threads, rather than just one of them, acquire a happens-
before dependency on the broadcasting thread at the point it did the broadcast.
• A thread T2 that continues after completing sem_wait on a semaphore that thread T1 posts on, acquires a happens-
before dependence on the posting thread, a bit like dependencies caused mutex unlock-lock pairs. However, since
a semaphore can be posted on many times, it is unspecified from which of the post calls the wait call gets its
happens-before dependency.
• For a group of threads T1 .. Tn which arrive at a barrier and then move on, each thread after the call has a happens-
after dependency from all threads before the barrier.
• A newly-created child thread acquires an initial happens-after dependency on the point where its parent created it.
That is, all memory accesses performed by the parent prior to creating the child are regarded as happening-before
all the accesses of the child.
• Similarly, when an exiting thread is reaped via a call to
pthread_join
, once the call returns, the reaping thread
acquires a happens-after dependency relative to all memory accesses made by the exiting thread.
In summary: Helgrind intercepts the above listed events, and builds a directed acyclic graph represented the collective
happens-before dependencies. It also monitors all memory accesses.
If a location is accessed by two different threads, but Helgrind cannot find any path through the happens-before graph
from one access to the other, then it reports a race.
There are a couple of caveats:
• Helgrind doesn’t check for a race in the case where both accesses are reads. That would be silly, since concurrent
reads are harmless.
• Two accesses are considered to be ordered by the happens-before dependency even through arbitrarily long chains of
synchronisation events. For example, if T1 accesses some location L, and then
pthread_cond_signals
T2,
which later
pthread_cond_signals
T3, which then accesses L, then a suitable happens-before dependency
exists between the first and second accesses, even though it involves two different inter-thread synchronisation
events.
7.4.3. Interpreting Race Error Messages
Helgrind’s race detection algorithm collects a lot of information, and tries to present it in a helpful way when a race is
detected. Here’s an example:
113