#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);
}
#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
#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.