Parallel Programming - Finished pthreads
[matches/honours.git] / course / semester2 / pprog / assignment1 / mthread / test_barrier.c
diff --git a/course/semester2/pprog/assignment1/mthread/test_barrier.c b/course/semester2/pprog/assignment1/mthread/test_barrier.c
new file mode 100644 (file)
index 0000000..d2efebb
--- /dev/null
@@ -0,0 +1,90 @@
+#include "barrier.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "barrier.c"
+
+/**
+ * @file test_barrier.c
+ * @purpose Test the barrier!
+ * @author Sam Moore (20503628) 2012
+ */
+
+// Compile with gcc --std=c99 -o test_barrier test_barrier.c -lpthread
+// Run with ./test_barrier
+// Expected output:
+//     All worker threads print "Hello" before all worker threads print "Goodbye"
+//     At any point, the "Boss" reports that it is waiting for "Hello" to be said, and goes to sleep.
+//     At some point whilst worker threads say "Goodbye", the "Boss" wakes up and reports that "Hello" has been said.
+//     The Boss should *never* report that "Hello" has been said until all workers say "Hello". 
+//     But it may report that it is waiting for "Hello" to be said at any time.
+//     Confused yet? I am, and I wrote this!
+//     NOTE: Two barriers are required to prevent deadlocking!
+
+
+pthread_mutex_t mutex_printf; // Printing is not thread safe! Mutex needed!
+Barrier worker_barrier[2];
+
+void * Worker(void * args)
+{
+       
+       //while (true) // Comment out to only test one step
+       {
+               Barrier_Enter(&worker_barrier[0]); //  Workers are now printing "Hello"
+
+               pthread_mutex_lock(&mutex_printf);
+               printf("Worker %p: Hello\n", (args)); // Only one thread can print at a time
+               pthread_mutex_unlock(&mutex_printf);
+
+               sleep(1);
+               Barrier_Join(&worker_barrier[0]);
+
+               pthread_mutex_lock(&mutex_printf);
+               printf("\tWorker %p: Goodbye\n", (args)); // Only one thread can print at a time
+               pthread_mutex_unlock(&mutex_printf);
+               
+
+               Barrier_Join(&worker_barrier[1]); // If we replace this with:
+               //Barrier_Join(&worker_barrier[0]); 
+               // Then there is (usually) a deadlock, because the first thread to leave the barrier 
+               // immediately reactivates it, and other threads are unable to leave.
+       
+       }
+}
+
+void * Boss(void * args)
+{
+       //while (true)
+       {
+               pthread_mutex_lock(&mutex_printf);
+               printf("Boss is waiting for \"Hello\" to be said.\n", (args)); // Only one thread can print at a time
+               pthread_mutex_unlock(&mutex_printf);            
+               Barrier_Wait(&worker_barrier[0]);
+               pthread_mutex_lock(&mutex_printf);
+               printf("Boss continues now that workers have said \"Hello\".\n", (args)); // Only one thread can print at a time
+               pthread_mutex_unlock(&mutex_printf);
+               sleep(2);
+               
+       }
+}
+
+int main(int argc, char ** argv)
+{
+       #define NUM_THREADS 4
+       pthread_t worker[NUM_THREADS];
+       pthread_t boss;
+       
+       Barrier_Init(&worker_barrier[0], NUM_THREADS); // Initialise barriers with number of contributing threads
+       Barrier_Init(&worker_barrier[1], NUM_THREADS);
+
+       pthread_create(&boss, NULL, Boss, NULL); //Start boss
+
+       for (long i = 0; i < NUM_THREADS; ++i)
+               pthread_create(worker+i, NULL, Worker, (void*)(i)); // Start all threads
+
+       for (int i = 0; i < NUM_THREADS; ++i) // Join threads
+               pthread_join(worker[i], NULL);
+       return 0;
+}

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