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
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)
{
continue;
}
-
-
-
- workers_busy = options.num_threads; //All threads working
-
//Compute forces
for (unsigned i = 0; i < options.num_threads; ++i)
{
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)
}
//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);
- }
}
}
{
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);
}
/**
{
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);
}
/**
*/
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;
}
*/
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;
}
{
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
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));
+}
#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);
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