JMU
Notifying Threads of State Changes
in Pthreads


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Review
The Good and the Bad
A Possible Remedy
A Possible Remedy (cont.)
unixexamples/conditionvariables/tax1.c
        #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tax_lib.h"

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static int should = -1;         // Shared variable

static void
*thread_entry(void *arg)
{
  pthread_mutex_lock(&mutex);

  // Start of critical section
  if (should_tax()) should = 1;
  else              should = 0;
  // End of critical section
  
  pthread_mutex_unlock(&mutex);
  
  record_status(); // This takes a long time

  return NULL;
}

int
main(void)
{
  float       rate, sales, tax;
  int         waiting;
  pthread_t   helper;
  void        *result;

  pthread_create(&helper, NULL, thread_entry, NULL);
  
  rate = 0.05;
  sales = total_sales();

  waiting = 1;
  while (waiting) // Poll until the helper thread is done
    {
      pthread_mutex_lock(&mutex);
      // Start of critical section
      if (should != -1) waiting = 0;
      // End of critical section
      pthread_mutex_unlock(&mutex);
    }

  // Start of critical section
  if (should) tax = sales * rate;
  else        tax = 0.0;
  // End of critical section
  
  printf("Tax: %5.2f\n", tax);
  pthread_join(helper, &result);
  exit(0);
}
        
Two Observations
A Good Mechanism for Indicating State Changes
Creating Condition Variables
Creating Condition Variables (cont.)
The Pattern
The Pattern (cont.)
The Blocking Thread in Detail
Blocking: pthread_cond_wait() pthread_cond_wait
int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
Purpose:
Wait/block on a condition variable
Details:
cv The condition variable to wait for
mutex The mutex associated with the condition variable
Return 0 on success; a positive error number on error
#include <pthread.h> pthread.h

When Called: mutex is relinquished and the calling thread is blocked.

When Unblocked: mutex is obtained (so that the shared variable can be used).

Blocking (cont.)
Notification
Notification (cont.): pthread_cond_signal() pthread_cond_signal
int pthread_cond_signal(pthread_cond_t *cv)
Purpose:
Notify a single (arbitrary) thread that is blocking on a condition variable
Details:
cv The condition variable the threads are/may be blocking on
Return 0 on success; a positive error number on error
#include <pthread.h> pthread.h
Notification (cont.): pthread_cond_broadcast() pthread_cond_broadcast
int pthread_cond_broadcast(pthread_cond_t *cv)
Purpose:
Notify all threads that are blocking on a condition variable
Details:
cv The condition variable the threads are/may be blocking on
Return 0 on success; a positive error number on error
#include <pthread.h> pthread.h

Note: All blocking threads will be notified but which one(s) are scheduled is arbitrary.

An Example
unixexamples/conditionvariables/tax2.c
        #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tax_lib.h"

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  cv    = PTHREAD_COND_INITIALIZER;
static int should = -1;         // Shared variable

static void
*thread_entry(void *arg)
{
  pthread_mutex_lock(&mutex);

  // Start of critical section
  if (should_tax()) should = 1;
  else              should = 0;
  // End of critical section
  
  pthread_mutex_unlock(&mutex);

  pthread_cond_broadcast(&cv);
  
  record_status(); // This takes a long time

  return NULL;
}



int
main(void)
{
  float       rate, sales, tax;
  pthread_t   helper;
  void        *result;

  pthread_create(&helper, NULL, thread_entry, NULL);
  
  rate = 0.05;
  sales = total_sales();

  pthread_mutex_lock(&mutex);

  while (should == -1)
    {
      pthread_cond_wait(&cv, &mutex);
    }
  
  if (should) tax = sales * rate;
  else        tax = 0.0;

  pthread_mutex_unlock(&mutex); // Not necessary for this example
  
  printf("Tax: %5.2f\n", tax);
  pthread_join(helper, &result);
  exit(0);
}
        
Dynamic Initialization: pthread_cond_init() pthread_cond_init
int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *attr)
Purpose:
Initialize a condition variable
Details:
cv The condition variable to be initialized
attr The attributes to use (of NULL for the default attributes)
Return 0 on success; a positive error number on error
#include <pthread.h> pthread.h
Destruction
Destruction (cont.): pthread_cond_destroy() pthread_cond_destroy
int pthread_cond_destroy(pthread_cond_t *cv)
Purpose:
Indicate that a condition variable will no longer be used
Details:
cv The condition variable to be destroyed
Return 0 on success; a positive error number on error
#include <pthread.h> pthread.h