user997112
user997112

Reputation: 30615

How does this pthread_cond_wait() example work?

I got the below code from this website:

https://computing.llnl.gov/tutorials/pthreads/#Abstract

This simple example code demonstrates the use of several Pthread condition variable routines. The main routine creates three threads. Two of the threads perform work and update a "count" variable. The third thread waits until the count variable reaches a specified value.

My question is- how does the below code ensure that one of the two worker threads doesn't lock on the mutex before the watcher thread locks on it? If this was to happen, the watcher thread would be locked out and pthread_cond_wait(&count_threshold_cv, &count_mutex) would never get called?

I am under the assumption pthread_create() actually begins the thread too. Is the only reason this works because the pthread_create() for the watcher thread begins before the pthread_create() for the two worker threads?! Surely this is not cast-iron and the scheduling could cause a worker thread to begin before the watcher thread? Even the compiler could potentially re-order these lines of code?

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define NUM_THREADS  3
#define TCOUNT 10
#define COUNT_LIMIT 12

int     count = 0;
int     thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;

void *inc_count(void *t) 
{
  int i;
  long my_id = (long)t;

  for (i=0; i<TCOUNT; i++) {
    pthread_mutex_lock(&count_mutex);
    count++;

    /* 
    Check the value of count and signal waiting thread when condition is
    reached.  Note that this occurs while mutex is locked. 
    */
    if (count == COUNT_LIMIT) {
      pthread_cond_signal(&count_threshold_cv);
      printf("inc_count(): thread %ld, count = %d  Threshold reached.\n", 
             my_id, count);
      }
    printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", 
       my_id, count);
    pthread_mutex_unlock(&count_mutex);

    /* Do some "work" so threads can alternate on mutex lock */
    sleep(1);
    }
  pthread_exit(NULL);
}

void *watch_count(void *t) 
{
  long my_id = (long)t;

  printf("Starting watch_count(): thread %ld\n", my_id);

  /*
  Lock mutex and wait for signal.  Note that the pthread_cond_wait 
  routine will automatically and atomically unlock mutex while it waits. 
  Also, note that if COUNT_LIMIT is reached before this routine is run by
  the waiting thread, the loop will be skipped to prevent pthread_cond_wait
  from never returning. 
  */
  pthread_mutex_lock(&count_mutex);
  while (count<COUNT_LIMIT) {
    pthread_cond_wait(&count_threshold_cv, &count_mutex);
    printf("watch_count(): thread %ld Condition signal received.\n", my_id);
    count += 125;
    printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
    }
  pthread_mutex_unlock(&count_mutex);
  pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
  int i, rc;
  long t1=1, t2=2, t3=3;
  pthread_t threads[3];
  pthread_attr_t attr;

  /* Initialize mutex and condition variable objects */
  pthread_mutex_init(&count_mutex, NULL);
  pthread_cond_init (&count_threshold_cv, NULL);

  /* For portability, explicitly create threads in a joinable state */
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_create(&threads[0], &attr, watch_count, (void *)t1);
  pthread_create(&threads[1], &attr, inc_count, (void *)t2);
  pthread_create(&threads[2], &attr, inc_count, (void *)t3);

  /* Wait for all threads to complete */
  for (i=0; i<NUM_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }
  printf ("Main(): Waited on %d  threads. Done.\n", NUM_THREADS);

  /* Clean up and exit */
  pthread_attr_destroy(&attr);
  pthread_mutex_destroy(&count_mutex);
  pthread_cond_destroy(&count_threshold_cv);
  pthread_exit(NULL);

}

Upvotes: 0

Views: 5448

Answers (2)

nos
nos

Reputation: 229108

My question is- how does the below code ensure that one of the two worker threads doesn't lock on the >mutex before the watcher thread locks on it?

The code doesn't need to ensure that. It doesn't depend on the watcher thread calling pthread_cond_wait().

The watcher thread checks count<COUNT_LIMIT, this is the actual condition the thread care about - or rather the inverse, when count >= COUNT_LIMIT - the watcher thread knows that the other threads are done.

The pthread condition variable used in pthread_cond_wait() is just needed in case the threads are not done, so the watcher thread can be put to sleep and woken up to check the condition it cares about.

That said, the example looks a tad silly, it's not quite clear what watcher thread wants to achieve by doing count += 125;

Upvotes: 2

Yuri
Yuri

Reputation: 351

the comment in your code explains that you do not have to worry about that:

Also, note that if COUNT_LIMIT is reached before this routine is run by the waiting thread, the loop will be skipped to prevent pthread_cond_wait from never returning.

in fact, if you notice, the while loop is run only if COUNT_LIMIT is not already reached by count. If that is the case, the pthread_cond_signal is not called at all.

Upvotes: 0

Related Questions