PFUNC  1.0
pfunc/barrier.hpp
Go to the documentation of this file.
00001 #ifndef PFUNC_BARRIER_HPP
00002 #define PFUNC_BARRIER_HPP
00003   
00010 #include <pfunc/config.h>
00011 #include <pfunc/pfunc_common.h>
00012 #include <pfunc/no_copy.hpp>
00013 #include <pfunc/exception.hpp>
00014 #include <pfunc/pfunc_atomics.h>
00015 #include <pfunc/environ.hpp>
00016 
00017 #if PFUNC_HAVE_FUTEX == 1
00018 #include <pfunc/futex.h>
00019 
00020 namespace pfunc { namespace detail {
00021   struct barrier : public no_copy {
00022     ALIGN64 unsigned barrier_size; 
00023     ALIGN64 unsigned barrier_phase; 
00024     ALIGN64 unsigned barrier_count; 
00026     barrier () : barrier_size (0), barrier_phase (0), barrier_count (0) {}
00027 
00031     void initialize (const unsigned int& size) { 
00032       barrier_size = barrier_count = size; 
00033     }
00034  
00038     void operator() () {
00039       unsigned my_phase = barrier_phase; 
00040 
00042       if (1 == pfunc_fetch_and_add_32 (&barrier_count, -1)) {
00043         barrier_count = barrier_size;
00044         barrier_phase = ~barrier_phase;
00045         futex_wake (reinterpret_cast<int*>(&barrier_phase), INT_MAX);
00046       } else {
00047         while (barrier_phase == my_phase) {
00049           for (unsigned int i = 0; i < 2000000; i++) {
00050             if (my_phase == barrier_phase) cpu_relax ();
00051             else break;
00052           }
00054           futex_wait (reinterpret_cast<int*>(&barrier_phase), my_phase);
00055         }
00056       }
00057     }
00058   };
00059 } /* namespace detail */ } /* namespace pfunc */
00060 
00061 #elif PFUNC_HAVE_PTHREADS == 1 || PFUNC_WINDOWS == 1
00062 #include <pfunc/mutex.hpp>
00063 #include <pfunc/cond.hpp>
00064 
00065 namespace pfunc { namespace detail {
00066   struct barrier {
00067     ALIGN64 volatile bool barrier_phase; 
00068     ALIGN64 volatile unsigned int barrier_count; 
00069     ALIGN64 unsigned int barrier_size; 
00070     mutex lck;
00071     cond cnd;
00072     PFUNC_DEFINE_EXCEPT_PTR()
00073 
00074     barrier () PFUNC_CONSTRUCTOR_TRY_BLOCK() : 
00075         barrier_phase (true), barrier_count (0), barrier_size (0) 
00076         PFUNC_EXCEPT_PTR_INIT() {}
00077     PFUNC_CATCH_AND_RETHROW(barrier,barrier)
00078 
00079     ~barrier () { PFUNC_EXCEPT_PTR_CLEAR() }
00080 
00081     void initialize (const unsigned int& size) { barrier_size = size; }
00082  
00084     void operator() () {
00085       PFUNC_START_TRY_BLOCK()
00086       lck.lock (); 
00087       volatile bool my_phase = barrier_phase;
00088       ++barrier_count;
00089       if (barrier_count == barrier_size) {
00090         barrier_count = 0;
00091         barrier_phase = !barrier_phase;
00092         cnd.broadcast ();
00093         lck.unlock ();
00094       } else {
00095         while (my_phase == barrier_phase) cnd.wait (lck);
00096         lck.unlock ();
00097       }
00098       PFUNC_END_TRY_BLOCK()
00099       PFUNC_CATCH_AND_RETHROW(barrier,paranthesis)
00100     }
00101   };
00102 } /* namespace detail */ } /* namespace pfunc */
00103 #endif
00104 
00105 #endif // PFUNC_HPP