Quantcast
Channel: Understanding pthreads locks and condition variables - Stack Overflow
Viewing all articles
Browse latest Browse all 3

Answer by Chris Hall for Understanding pthreads locks and condition variables

$
0
0

First, you are doing the gcd() work while holding the lock... so (a) only one thread will do any work at any one time, though (b) that does not entirely explain why only one thread appears to do (nearly) all the work -- as KamilCuk says, it may be that there is so little work to do, that it's (nearly) all done before the second thread wakes up properly. [More exotic, there may be some latency between thread 'a' unlocking the mutex and another thread starting to run, such that thread 'a' can acquire the mutex before another thread gets there.]

POSIX says that when a mutex is unlocked, if there are waiters then "the scheduling policy shall determine which thread shall acquire the mutex". The default "scheduling policy" is (to the best of my knowledge) implementation defined.

You could try a couple of things: (1) use a pthread_barrier_t to hold all the threads at the start of thread_function() until they are all running; (2) use sched_yield(void) after pthread_mutex_unlock() to prompt the system into running the newly runnable thread.

Second, you should not under any circumstance treat a 'condition variable' as a signal. For main() to know that all threads have finished you need a count -- which could be a pthread_barrier_t; or it could be simple integer, protected by a mutex, with a 'condition variable' to hold the main thread on while it waits; or it could be a count (in main()) and a semaphore (posted once by each thread as it exits).

Third, you show pthread_cond_wait(&cv, &lock); in main(). At that point main()must own lock... and it matters when that happened. But: as it stands, the first thread to find the list empty will kick cv, and main() will proceed, even though other threads are still running. Though once main() does re-acquire lock, any threads which are then still running will either be exiting or will be stuck on the lock. (It's a mess.)


In general, the template for using a 'condition variable' is:

    pthread_mutex_lock(&...lock) ;    while (!(... thing we need ...))      pthread_cond_wait(&...cond_var, &...lock) ;    ... do stuff now we have what we need ....    pthread_mutex_unlock(&...lock) ;

NB: a 'condition variable' does not have a value... despite the name, it is not a flag to signal that some condition is true. A 'condition variable' is, essentially, a queue of threads waiting to be re-started. When a 'condition variable' is signaled, at least one waiting thread will be re-started -- but if there are no threads waiting, nothing happens, in particular the (so called) 'condition variable' retains no memory of the signal.

In the new code, following the above template, main() should:

    /* wait for threads .... */    status = pthread_mutex_lock(&thread_lock);    chcek_status(status);    while (thread_finished_count != 3)      {        pthread_cond_wait(&thread_cv, &thread_lock) ;        chcek_status(status);      } ;    status = pthread_mutex_unlock(&thread_lock) ;    chcek_status(status);

So what is going on here ?

  1. main() is waiting for thread_finished_count == 3

  2. thread_finished_count is a shared variable "protected" by the thread_lock mutex.

    ...so it is incremented in thread_function() under the mutex.

    ...and main() must also read it under the mutex.

  3. if main() finds thread_finished_count != 3 it must wait.

    to do that it does: pthread_cond_wait(&thread_cv, &thread_lock), which:

    • unlocks thread_lock

    • places the thread on the thread_cv queue of waiting threads.

    and it does those atomically.

  4. when thread_function() does the pthread_cond_signal(&thread_cv) it wakes up the waiting thread.

  5. when the main() thread wakes up, it will first re-acquire the thread_lock...

    ...so it can then proceed to re-read thread_finished_count, to see if it is now 3.

FWIW: I recommend not destroying the mutexes etc until after all the threads have been joined.


Viewing all articles
Browse latest Browse all 3

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>