6

I am trying to better understand how to use pthread_cond_wait() and how it works. I am just looking for a bit of clarification to an answer I saw on this site.

The answer is the last reply on this page

understanding of pthread_cond_wait() and pthread_cond_signal()

I am wondering how this would look with three threads. Imagine Thread 1 wants to tell Thread 2 and Thread 3 to wake up

For example

pthread_mutex_t mutex;
pthread_cond_t condition;

Thread 1:

pthread_mutex_lock(&mutex);

/*Initialize things*/

pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 2 & 3

/*Do other things*/

Thread 2:

pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
    pthread_cond_wait(&condition, &mutex); //wait for the condition
}
pthread_mutex_unlock(&mutex);

/*Do work*/

Thread 3:

pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
    pthread_cond_wait(&condition, &mutex); //wait for the condition
}
pthread_mutex_unlock(&mutex);

/*Do work*/

I am wondering if such a setup is valid. Say that Thread 2 and 3 relied on some intialization options that thread 1 needs to process.

roschach
  • 8,390
  • 14
  • 74
  • 124
user2327195
  • 263
  • 3
  • 10
  • 2
    You can have two threads waiting on the same condition, yes. When you call `pthread_cond_signal()`, only one of them will wake, but the woken thread could signal again to wake the next waiting thread... or you could use `pthread_cond_broadcast()` instead to wake all threads waiting on the condition. – Dmitri Jul 15 '15 at 21:13

4 Answers4

6

First: If you wish thread #1 to wake up thread #2 and #3, it should use pthread_cond_broadcast.

Second: The setup is valid (with broadcast). Thread #2 and #3 are scheduled for wakeup and they will try to reacquire the mutex as part of waking up. One of them will, the other will have to wait for the mutex to be unlocked again. So thread #2 and #3 access the critical section sequentically (to re-evaluate the condition).

Ilario Pierbattista
  • 3,175
  • 2
  • 31
  • 41
Laurent Michel
  • 395
  • 1
  • 5
  • Downvote. Doesn't address the severe problem that `while(!condition)` uses a variable of type `pthread_cond_t` as a boolean, which makes no sense. `pthread_cond_t` is an opaque type - it could be anything, and it's quite unlikely to have the boolean value a user may expect. Other answers explain how to use `pthread_cond_wait()` correctly. – jcsahnwaldt Reinstate Monica Nov 04 '19 at 19:10
5

If I understand correctly, you want thr#2 and thr#3 ("workers") to block until thr#1 ("boss") has performed some initialization.

Your approach is almost workable, but you need to broadcast rather than signal, and are missing a predicate variable separate from your condition variable. (In the question you reference, the predicate and condition variables were very similarly named.) For example:

pthread_mutex_t mtx;
pthread_cond_t  cv;
int             initialized = 0;  // our predicate of interest, signaled via cv

...

// boss thread
  initialize_things();
  pthread_mutex_lock(&mtx);
  initialized = 1;
  pthread_cond_broadcast(&cv);
  pthread_mutex_unlock(&mtx);
  ...

// worker threads
  pthread_mutex_lock(&mtx);
  while (! initialized) {
    pthread_cond_wait(&cv, &mtx);
  }
  pthread_mutex_unlock(&mtx);
  do_things();

That's common enough that you might want to combine the mutex/cv/flag into a single abstraction. (For inspiration, see Python's Event object.) POSIX barriers which are another way of synchronizing threads: every thread waits until all threads have "arrived." pthread_once is another way, as it runs a function once and only once no matter how many threads call it.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
3

pthread_cond_signal wakes up one (random) thread waiting on the cond variable. If you want to wake up all threads waiting on this cond variable use pthread_cond_broadcast.

roschach
  • 8,390
  • 14
  • 74
  • 124
MK.
  • 33,605
  • 18
  • 74
  • 111
0

Depending what you are doing on the critical session there might be also another solution apart from the ones in the previous answers.

Suppose thread1 is executing first (i.e. it is the creator thread) and suppose thread2 and thread3 do not perform any write in to shared resource in the critical session. In this case with pthread_cond_wait you are forcing one thread to wait the other when actually there is no need.

You can use read-write mutex of type pthread_rwlock_t. Basically the thread1 performs a write-lock so the other threads will be blocked when trying to acquire a read-lock.

The functions for this lock are quite self-explanatory:

//They return: 0 if OK, error number on failure
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
    const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

When thread1 has finished its initialization it unlocks. The other threads will perform a read-lock and since more read-locks can co-exist they can execute simultaneously. Again: this is valid if you do not perform any write in thread2&3 on the shared resources.

roschach
  • 8,390
  • 14
  • 74
  • 124