Parallel Programming - Finished pthreads
[matches/honours.git] / course / semester2 / pprog / assignment1 / mthread / barrier.c
1 /**
2  * @file barrier.c
3  * @purpose Implementation of a pthread barrier
4  * @author Sam Moore (20503628) 2012
5  */
6
7 #include "barrier.h"
8
9
10 /**
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
16  *
17  */
18 void Barrier_Init(Barrier * b, unsigned total_threads)
19 {
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.
24         b->active = false;
25 }       
26
27 void Barrier_Enter(Barrier * b)
28 {
29         b->active = true;
30 }       
31
32 void Barrier_Wait(Barrier * b)
33 {
34         
35         pthread_mutex_lock(&(b->mutex));
36         while (b->active)
37         {
38                 pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
39         }
40         pthread_mutex_unlock(&(b->mutex));
41 }
42
43 /**
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
46  *
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.
49  *
50  * @param b - The barrier
51  */
52 void Barrier_Join(Barrier * b)
53 {
54         pthread_mutex_lock(&(b->mutex));
55
56         if (b->threads_done >= b->total_threads) // The barrier is not active
57         {
58                 b->threads_done = 0; // Activate the barrier
59                 b->active = true;
60         }
61
62         b->threads_done += 1;
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)
65         {
66                 pthread_cond_broadcast(&(b->threads_done_cv));
67                 b->active = false;
68                 //printf("\tThread wakes up other threads\n");
69         }
70         else
71         {
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));
75
76                 //printf("\tThread done with barrier\n");
77                 
78         }
79
80         
81         //printf("\tThread leaves barrier; %u threads done out of %u\n", b->threads_done, b->total_threads);
82         pthread_mutex_unlock(&(b->mutex));
83
84 }
85
86
87 void Barrier_ForceExit(Barrier * b)
88 {
89         pthread_mutex_lock(&(b->mutex));
90         pthread_cond_broadcast(&(b->threads_done_cv));  
91         b->active = false;
92         pthread_mutex_unlock(&(b->mutex));
93 }       
94
95 /**
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
103  */
104 void * Barrier_JoinCall(Barrier * b, void*(*call)(void*), void * args)
105 {
106         void * result = NULL;
107         pthread_mutex_lock(&(b->mutex));
108
109         if (b->threads_done >= b->total_threads)
110         {
111                 b->threads_done = 0;    
112                 b->active = true;
113         }
114
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)
118         {
119                 result = (*call)(args);
120                 pthread_cond_broadcast(&(b->threads_done_cv));
121                 b->active = false;
122                 //printf("\tThread wakes up other threads\n");
123         }
124         else
125         {
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");
130                 
131         }
132         
133         pthread_mutex_unlock(&(b->mutex));
134
135         return result;
136 }
137
138 //EOF
139
140

UCC git Repository :: git.ucc.asn.au