// Author: Jochen Kerdels #include #include "TBarrier.h" //_____________________________________________________________ // // The TBarrier class provides a synchronization mechanism for // a group of TThreads. // // A barrier is initialized with the number of threads that have // to run into the barrier in order to tear the barrier down and // continue processing. This mechanism is typically used if a // stepwise task should be processed by a number of threads in // parallel and where the threads have to synchronize in between // the single steps. // // If, for example, the following code snippet should be executed // in parallel by four threads, we would initialize the barrier // with a size of four: // // while(1) { // // doStep1(); // // barrier->Wait(); // // doStep2(); // // barrier->Wait(); // // doStep3(); // // barrier->Wait(); // // } // // Internally the barrier uses a counting variable which is protected // by a TMutex. The threads themselves are synchronized by a TCondition. // ClassImp(TBarrier); TBarrier::TBarrier(UInt_t bSize) : TObject(), fBarrierSize(bSize), fCurrentCnt(0), fCondMutex(), fCondition(&fCondMutex) { // The parameter bSize sets the barrier size, i.e. the number of // threads that have to run into the barrier upon which the barrier // breaks and the processing of the threads continues. // // The default value for bSize is 1. // // If bSize is 0, it will be treated as 1. if (fBarrierSize == 0) fBarrierSize = 1; } TBarrier::~TBarrier() { // Upon destruction potentially waiting threads are released. fCondMutex.Lock(); if (fCurrentCnt > 0) { fCurrentCnt = 0; fCondition.Broadcast(); } fCondMutex.UnLock(); } void TBarrier::Wait() { // In order to run into the barrier a thread has to call this method. // A call will increase fCurrentCnt and compare it to fBarrierSize. // If fCurrentCnt is greater or equal to fBarrierSize all waiting // threads are released. Otherwise, the thread itself goes into a // waiting state. fCondMutex.Lock(); if ( (++fCurrentCnt) >= fBarrierSize ) { fCurrentCnt = 0; fCondition.Broadcast(); fCondMutex.UnLock(); return; } fCondition.Wait(); fCondMutex.UnLock(); } void TBarrier::setBarrierSize(UInt_t bSize) { // Sets a new barrier size. If there are pending threads and the // barrier size becomes equal or smaller than the number of waiting // threads, the waiting threads are released. // // Setting the barrier size to 1 effectively disables the barrier // and releases all pending threads. fCondMutex.Lock(); fBarrierSize = bSize; if (fBarrierSize == 0) fBarrierSize = 1; if (fCurrentCnt >= fBarrierSize) { fCurrentCnt = 0; fCondition.Broadcast(); } fCondMutex.UnLock(); } UInt_t TBarrier::getBarrierSize() { // Returns the current barrier size. return fBarrierSize; } UInt_t TBarrier::getCurrentCnt() { // Returns the number of threads currently inside the barrier. return fCurrentCnt; }