Loyola College in Maryland

CS 702 Operating Systems
Fall 2004


Loyola College > Department of Computer Science > Dr. James Glenn > CS 702 > Examples and Lecture Notes > Barrier

barrier_test.cpp

#include <iostream>
#include <sstream>

#include <unistd.h>

#include "barrier.h"

void *delay(void* args);

/**
 * A demonstration of a barrier.  Several threads are created.  Each executes
 * a different amount of time; a barrier is used to ensure that none terminate
 * before the last one has finished processing.
 *
 * @author Jim Glenn
 * @version 0.1 2/17/2004
 */

int main(int argc, char **argv)
{
  // parse and validate command line arguments

  if (argc != 2)
    {
      std::cerr << "USAGE: " << argv[0] << " num-threads" << std::endl;
      return 1;
    }

  std::stringstream args;
  for (int a = 1; a < argc; a++)
    args << argv[a] << ' ';

  int threads;
  args >> threads;

  if (threads <= 0)
    {
      std::cerr << argv[0] << ": num-threads must be positive" << std::endl;
      return 1;
    }

  // create a barrier for the threads to cross

  Barrier bar(threads);

  // create the threads

  for (int t = 0; t < threads; t++)
    {
      pthread_t id;
      
      pthread_create(&id, NULL, delay, &bar);
      pthread_detach(id);
    }

  // terminate main without killing the whole process

  pthread_exit(NULL);

  // note that the Barrier destructor is never run so if there was cleanup
  // that it needed to perform that cleanup would never get done -- it would
  // be better to have main wait for all threads to finish and then
  // fall off the end
}

/**
 * Entry point for a thread that waits a random length of time,
 * crosses a barrier, and terminates.
 *
 * @param args a pointer to the barrier to cross before termination
 */

void *delay(void *args)
{
  Barrier *bar = reinterpret_cast<Barrier *>(args);

  sleep(random() & 7); // sleep 0-7 seconds

  std::cerr << "a thread is crossing the barrier" << std::endl;

  bar->cross();

  std::cerr << "a thread is terminating" << std::endl;

  pthread_exit(NULL);
}

barrier.h

#ifndef __BARRIER_H__
#define __BARRIER_H__

#include <pthread.h>

/**
 * A barrier for thread synchronization.
 *
 * @author Jim Glenn
 * @version 0.1 10/14/2003
 */

class Barrier
{
public:
  /**
   * Creates a barrier that will hold the given number of threads.
   *
   * @param n the number of threads to cross this barrier
   */

  Barrier(int n);

  /**
   * Attempts to cross this barrier.  If not all threads have reached the
   * barrier, the calling thread is put to sleep until they have.
   *
   * @return true for one arbitrarily chosen thread that crosses this barrier
   */

  bool cross();

private:
  /**
   * The condition variable for this barrier.  The condition it represents
   * is "all threads have reached the barrier."
   */

  pthread_cond_t allHere;

  /**
   * The mutex for this barrier.  The mutex controls access to the fields.
   */

  pthread_mutex_t mutex;

  /**
   * Initializers for mutexes and condition variables.  Needed because
   * the constants defined in pthread.h are macros that confuse the
   * compiler in certain circumstances.
   */

  static const pthread_cond_t DEFAULT_COND;
  static const pthread_mutex_t DEFAULT_MUTEX;

  /**
   * The number of threads that should cross this barrier.
   */

  int count;

  /**
   * The number of threads that have reached this barrier.
   */

  int crossing;
};

#endif

barrier.cpp

#include <pthread.h>

#include "barrier.h"

const pthread_cond_t Barrier::DEFAULT_COND = PTHREAD_COND_INITIALIZER;
const pthread_mutex_t Barrier::DEFAULT_MUTEX = PTHREAD_MUTEX_INITIALIZER;

/**
 * Creates a barrier for the given number of threads to cross.
 *
 * @param n a positive number
 */

Barrier::Barrier(int n) :
  mutex(DEFAULT_MUTEX),
  allHere(DEFAULT_COND)
{
  count = n;
  crossing = 0;
}

/**
 * Attempt to cross this barrier.  If not all threads have reached this
 * barrier, the thread calling this method will be blocked.
 * Once the last thread has reached the barrier, all blocked threads will
 * be unblocked.
 *
 * @return true only for one thread that crosses the barrier
 */

bool Barrier::cross()
{
  bool result;

  pthread_mutex_lock(&mutex);

  // one more thread has reached

  crossing++;

  // if not all here, wait; otherwise we're the last one so wake up the others

  if (crossing < count)
    {
      pthread_cond_wait(&allHere, &mutex);
      result = false;
    }
  else
    {
      pthread_cond_broadcast(&allHere);
      crossing = 0; // reset so we can use this barrier again
      result = true;
    }

  pthread_mutex_unlock(&mutex);

  return result;
}

This code can also be downloaded from the files barrier_test.cpp, barrier.h, and barrier.cpp.