3 * @purpose Implementation of a pthread barrier
4 * @author Sam Moore (20503628) 2012
11 * @function Barrier_Init
12 * @purpose Initialise a Barrier
13 * Should only be called once for each Barrier
14 * @param b - The Barrier
15 * @param total_threads - Number of threads that will be participating in the barrier
18 void Barrier_Init(Barrier * b, unsigned total_threads)
20 b->total_threads = total_threads;
21 b->threads_done = total_threads; // All threads start as done.
22 // When Barrier_Join is called, the first entering thread will set threads_done to zero.
23 // Each thread joining the barrier increments threads_done, and sleep until all threads have joined.
27 void Barrier_Enter(Barrier * b)
32 void Barrier_Wait(Barrier * b)
35 pthread_mutex_lock(&(b->mutex));
38 pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
40 pthread_mutex_unlock(&(b->mutex));
44 * @function Barrier_Join
45 * @purpose A Barrier that waits for the required number of threads to enter it, before allowing all threads to continue
47 * This function should be called for each thread participating in the barrier.
48 * Barrier_Init should first be called with the correct total number of threads participating in the barrier.
50 * @param b - The barrier
52 void Barrier_Join(Barrier * b)
54 pthread_mutex_lock(&(b->mutex));
56 if (b->threads_done >= b->total_threads) // The barrier is not active
58 b->threads_done = 0; // Activate the barrier
63 //printf("Thread joins barrier %p, %u done out of %u\n", (void*)(b), b->threads_done, b->total_threads);
64 if (b->threads_done == b->total_threads)
66 pthread_cond_broadcast(&(b->threads_done_cv));
68 //printf("\tThread wakes up other threads\n");
72 //printf("\tThread waiting on barrier\n");
73 while (b->threads_done < b->total_threads) // Keep waiting as long as the barrier is active
74 pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
76 //printf("\tThread done with barrier\n");
81 //printf("\tThread leaves barrier; %u threads done out of %u\n", b->threads_done, b->total_threads);
82 pthread_mutex_unlock(&(b->mutex));
87 void Barrier_ForceExit(Barrier * b)
89 pthread_mutex_lock(&(b->mutex));
90 pthread_cond_broadcast(&(b->threads_done_cv));
92 pthread_mutex_unlock(&(b->mutex));
96 * @function Barrier_JoinCall
97 * @purpose Behaves as Barrier_Join(b), except the last thread in the barrier calls the specified function
98 * (This is a hack to get code to execute in one thread without additional mutexes when the code happens just after a barrier anyway).
99 * (Could make the first thread execute the function for efficiency, but for the nbody simulator that would make the performance metric wrong)
100 * @param b - The barrier
101 * @param call - Function pointer to call (function pointers are fun!)
102 * @param args - Arguments to the function
104 void * Barrier_JoinCall(Barrier * b, void*(*call)(void*), void * args)
106 void * result = NULL;
107 pthread_mutex_lock(&(b->mutex));
109 if (b->threads_done >= b->total_threads)
115 b->threads_done += 1;
116 //printf("Thread joins barrier %p, %u done out of %u\n", (void*)(b), b->threads_done, b->total_threads);
117 if (b->threads_done == b->total_threads)
119 result = (*call)(args);
120 pthread_cond_broadcast(&(b->threads_done_cv));
122 //printf("\tThread wakes up other threads\n");
126 //printf("\tThread waiting on barrier\n");
127 while (b->threads_done < b->total_threads)
128 pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
129 //printf("\tThread done with barrier\n");
133 pthread_mutex_unlock(&(b->mutex));