Yeah, could be a "false positive".
On the other hand, think about this: The function
pthread_mutex_unlock() is
not just a single "atomic" CPU instruction; it is a complex function implemented in libpthread. All we really know is that, at some point in
pthread_mutex_unlock(), the mutex will be marked as "not currently locked", so that the other thread can proceed. But, does
pthread_mutex_unlock() return
immediately after that point? Is it guaranteed that
pthread_mutex_unlock() won't access the
pthread_mutex_t struct after that point, before returning? I don't think so, because this is an implementation detail that we
should not make any assumptions about. Better assume the "worst" case 😏
In other words, your
example() function does
not wait until
pthread_mutex_unlock() actually has fully
returned inside of the
runThread() function; it only waits until the
runThread() function has (at least)
begun its
pthread_mutex_unlock() operation.
Surely, any kind of "concurrent" or "interleaved"
pthread_mutex_lock() or
pthread_mutex_unlock() invocations on the
same pthread_mutex_t must always be safe, assuming that the
pthread_mutex_t was properly initialized. Meanwhile,
destorying the
pthread_mutex_t while an
pthread_mutex_unlock() still
might be in progress probably results in
undefined behavior!
I think it's a good guideline to only destroy "shared" resources after all (other) threads that might access those resources have terminated.
________
EDIT: Is it really necessary to create a new
pthread_mutex_t and
pthread_cond_t for each thread? You could simply create those
once and re-use them. This eliminates the need to destroy them (except when your program terminates). Note that your variables are declared
static, so you can only have
one mutex and
cond at a time anyways. Doesn't make much sense to destroy + re-create them continuously...
EDIT²: If you want to be sure that multiple threads have passed a certain point, consider using a
pthread_barrier:
https://www.daemon-systems.org/man/pthread_barrier.3.html
(But, of course, this creates the new problem of when to call the
pthread_barrier_destroy function 😏)