Parallel Programming - pthreads version
authorSam Moore <sam@daedalus.(none)>
Tue, 11 Sep 2012 12:26:15 +0000 (20:26 +0800)
committerSam Moore <sam@daedalus.(none)>
Tue, 11 Sep 2012 12:26:15 +0000 (20:26 +0800)
Implemented multithreaded barrier to save typing the same thing a billion more times

course/semester2/pprog/assignment1/mthread/nbody.c
course/semester2/pprog/assignment1/mthread/nbody.h

index f59b451..7504928 100644 (file)
@@ -15,15 +15,12 @@ pthread_t compute_thread; // The thread responsible for computations; it spawns
        
 pthread_t * worker_thread = NULL; //Array of worker threads responsible for Force and Position updates
 System * sub_system = NULL; //Array of Systems used to divide up the main "universe" System for worker threads
-pthread_mutex_t mutex_workers; // Mutex used for the barrier between Force and Position updates
-pthread_cond_t workers_done_cv; // Conditional used for the barrier between Force and Position updates
-unsigned workers_busy; // Number of workers currently doing something
 
 pthread_mutex_t mutex_runstate; // Mutex around the runstate
 
-pthread_mutex_t mutex_graphics; //Mutex between graphics and computation
-pthread_cond_t graphics_cv; //Condition used to start graphics or computation thread from the other
-bool graphics_busy = false; // Indicate if graphics is currently drawing
+Barrier worker_barrier;
+Barrier graphics_barrier;
+
 
 /**
  * @function Compute_Thread
@@ -86,6 +83,9 @@ void * Compute_Thread(void * arg)
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //Needs to be detached, so that memory can be reused.
 
+       
+       
+
        // The main computation loop
        while (true)
        {
@@ -110,11 +110,6 @@ void * Compute_Thread(void * arg)
                        continue;
                }
 
-               
-
-               
-               workers_busy = options.num_threads; //All threads working
-
                //Compute forces
                for (unsigned i = 0; i < options.num_threads; ++i)
                {
@@ -124,28 +119,19 @@ void * Compute_Thread(void * arg)
                                QuitProgram(true);
                                pthread_exit(NULL);
                        }       
+                       
                }
 
 
-
-               //Barrier - Wait for forces to be computed
-               pthread_mutex_lock(&mutex_workers);
-               while (workers_busy > 0)
-                       pthread_cond_wait(&workers_done_cv, &mutex_workers);
-               pthread_mutex_unlock(&mutex_workers);
+               Barrier_Wait(&worker_barrier);
 
                //All the forces are now computed
 
-               // Wait for graphics to finish drawing the last step
-               if (options.pedantic_graphics && options.draw_graphics)
+               if (options.draw_graphics && options.pedantic_graphics)
                {
-                       pthread_mutex_lock(&mutex_graphics);
-                       while (graphics_busy)
-                               pthread_cond_wait(&graphics_cv, &mutex_graphics);
-                       pthread_mutex_unlock(&mutex_graphics);
+                       Barrier_Wait(&graphics_barrier);
+                       Barrier_Enter(&graphics_barrier);
                }
-               
-               workers_busy = options.num_threads; //All threads working
 
                //Compute positions
                for (unsigned i = 0; i < options.num_threads; ++i)
@@ -159,23 +145,15 @@ void * Compute_Thread(void * arg)
                }
 
                //Wait for positions to be computed
-               pthread_mutex_lock(&mutex_workers);
-               while (workers_busy > 0)
-                       pthread_cond_wait(&workers_done_cv, &mutex_workers);
-               pthread_mutex_unlock(&mutex_workers);
+               Barrier_Wait(&worker_barrier);
+
 
                //Update number of steps computed
                universe.steps += 1;
 
+               if (options.draw_graphics && options.pedantic_graphics)
+                       Barrier_Leave(&graphics_barrier);
 
-               // Signal graphics thread to draw bodies
-               if (options.pedantic_graphics && options.draw_graphics)
-               {
-                       pthread_mutex_lock(&mutex_graphics);
-                       graphics_busy = true;
-                       pthread_cond_signal(&graphics_cv);
-                       pthread_mutex_unlock(&mutex_graphics);
-               }
 
        }
 }
@@ -190,10 +168,8 @@ void BeforeDraw()
 {
        if (!options.pedantic_graphics)
                return;
-       pthread_mutex_lock(&mutex_graphics);
-       while (!graphics_busy)
-               pthread_cond_wait(&graphics_cv, &mutex_graphics);
-       pthread_mutex_unlock(&mutex_graphics);
+       Barrier_Wait(&graphics_barrier);
+       Barrier_Enter(&graphics_barrier);
 }
 
 /**
@@ -207,10 +183,7 @@ void AfterDraw()
 {
        if (!options.pedantic_graphics)
                return;
-       pthread_mutex_lock(&mutex_graphics);
-       graphics_busy = false;
-       pthread_cond_signal(&graphics_cv);
-       pthread_mutex_unlock(&mutex_graphics);
+       Barrier_Leave(&graphics_barrier);
 }
 
 /**
@@ -220,16 +193,12 @@ void AfterDraw()
  */
 void * Force_Thread(void * s)
 {
-       
+       Barrier_Enter(&worker_barrier);
+
        System_Forces((System*)s, &universe); //Simple wrapper
 
-       pthread_mutex_lock(&mutex_workers);
-       workers_busy -= 1;      // Count this thread as done
-       if (workers_busy == 0)
-       {
-               pthread_cond_signal(&workers_done_cv); // All threads done; wake up the compute_thread
-       }
-       pthread_mutex_unlock(&mutex_workers);
+       Barrier_Leave(&worker_barrier);
+
        return NULL;
 }
 
@@ -240,16 +209,9 @@ void * Force_Thread(void * s)
  */
 void * Position_Thread(void * s)
 {
-       
+       Barrier_Enter(&worker_barrier);
        System_Positions((System*)s); // Simple wrapper
-
-       pthread_mutex_lock(&mutex_workers);
-       workers_busy -= 1; // Count this thread as done
-       if (workers_busy == 0)
-       {
-               pthread_cond_signal(&workers_done_cv); //All threads done; wake up the compute_thread
-       }
-       pthread_mutex_unlock(&mutex_workers);
+       Barrier_Leave(&worker_barrier);
        return NULL;
 }      
 
@@ -300,6 +262,9 @@ void Simulation_Run(int argc, char ** argv)
 {
        atexit(Thread_Cleanup);
 
+       Barrier_Init(&worker_barrier);
+       Barrier_Init(&graphics_barrier);
+
        if (options.draw_graphics)
        {
                // The graphics are enabled, so create a thread to do computations
@@ -314,3 +279,36 @@ void Simulation_Run(int argc, char ** argv)
        else
                Compute_Thread((void*)(&universe)); // Graphics are disabled, so do computations in the main thread
 }
+
+
+
+void Barrier_Init(Barrier * b)
+{
+       b->threads_busy = 0;
+}      
+
+void Barrier_Enter(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       b->threads_busy += 1;
+       pthread_mutex_unlock(&(b->mutex));
+}
+
+void Barrier_Leave(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       b->threads_busy -= 1;
+       if (b->threads_busy == 0)
+       {
+               pthread_cond_signal(&(b->threads_done_cv));
+       }
+       pthread_mutex_unlock(&(b->mutex));
+}
+
+void Barrier_Wait(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       while (b->threads_busy > 0)
+               pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
+       pthread_mutex_unlock(&(b->mutex));
+}
index f2eec0d..5950126 100644 (file)
@@ -10,6 +10,8 @@
 
 #define DEFAULT_WORKING_THREADS 2 
 
+#define PERSISTENT_THREADS //If defined, threads will not be continually destroyed and then respawned
+
 //Undefine default macros, replace with functions
 #undef Simulation_Run
 void Simulation_Run(int argc, char ** argv);
@@ -31,17 +33,16 @@ void * Position_Thread(void * system); //Thread - Compute positions for all obje
 
 void Thread_Cleanup(void); //Called at program exit to safely join computation thread
 
-extern pthread_t compute_thread; // ID of the thread that runs Compute_Thread. 
-extern pthread_mutex_t mutex_runstate; //Mutex around the "runstate" variable
-
-extern pthread_t * worker_thread; //Array of worker threads responsible for Force and Position updates
-extern System * sub_system; //Array of Systems used to divide up the main "universe" System for worker threads
-extern pthread_mutex_t mutex_workers;
-extern pthread_cond_t workers_done_cv;
-extern unsigned workers_busy;
-
-extern pthread_mutex_t mutex_graphics; // Mutex for graphics
-extern pthread_cond_t graphics_cv; //Condition used to start graphics or computation thread from the other
-extern bool graphics_busy;
+typedef struct
+{
+       pthread_mutex_t mutex;
+       unsigned threads_busy; // Counter of threads which are busy
+       pthread_cond_t threads_done_cv;
+} Barrier;
+
+void Barrier_Init(Barrier * b);
+void Barrier_Enter(Barrier * b);
+void Barrier_Leave(Barrier * b);
+void Barrier_Wait(Barrier * b);
 
 #endif //_NBODY_MTHREAD_H

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