1 /** 2 * The barrier module provides a primitive for synchronizing the progress of 3 * a group of threads. 4 * 5 * Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved. 6 * License: BSD style: $(LICENSE) 7 * Author: Sean Kelly 8 */ 9 module tango.core.sync.Barrier; 10 11 12 public import tango.core.Exception : SyncException; 13 private import tango.core.sync.Condition; 14 private import tango.core.sync.Mutex; 15 16 version( Win32 ) 17 { 18 private import tango.sys.win32.UserGdi; 19 } 20 else version( Posix ) 21 { 22 private import tango.stdc.errno; 23 private import tango.stdc.posix.pthread; 24 } 25 26 27 //////////////////////////////////////////////////////////////////////////////// 28 // Barrier 29 // 30 // void wait(); 31 //////////////////////////////////////////////////////////////////////////////// 32 33 34 /** 35 * This class represents a barrier across which threads may only travel in 36 * groups of a specific size. 37 */ 38 class Barrier 39 { 40 //////////////////////////////////////////////////////////////////////////// 41 // Initialization 42 //////////////////////////////////////////////////////////////////////////// 43 44 45 /** 46 * Initializes a barrier object which releases threads in groups of limit 47 * in size. 48 * 49 * Params: 50 * limit = The number of waiting threads to release in unison. 51 * 52 * Throws: 53 * SyncException on error. 54 */ 55 this( uint limit ) 56 in 57 { 58 assert( limit > 0 ); 59 } 60 body 61 { 62 m_lock = new Mutex; 63 m_cond = new Condition( m_lock ); 64 m_group = 0; 65 m_limit = limit; 66 m_count = limit; 67 } 68 69 70 //////////////////////////////////////////////////////////////////////////// 71 // General Actions 72 //////////////////////////////////////////////////////////////////////////// 73 74 75 /** 76 * Wait for the pre-determined number of threads and then proceed. 77 * 78 * Throws: 79 * SyncException on error. 80 */ 81 void wait() 82 { 83 synchronized( m_lock ) 84 { 85 uint group = m_group; 86 87 if( --m_count == 0 ) 88 { 89 m_group++; 90 m_count = m_limit; 91 m_cond.notifyAll(); 92 } 93 while( group == m_group ) 94 m_cond.wait(); 95 } 96 } 97 98 99 private: 100 Mutex m_lock; 101 Condition m_cond; 102 uint m_group; 103 uint m_limit; 104 uint m_count; 105 } 106 107 108 //////////////////////////////////////////////////////////////////////////////// 109 // Unit Tests 110 //////////////////////////////////////////////////////////////////////////////// 111 112 113 debug( UnitTest ) 114 { 115 private import tango.core.Thread; 116 117 118 unittest 119 { 120 int numThreads = 10; 121 auto barrier = new Barrier( numThreads ); 122 auto synInfo = new Object; 123 int numReady = 0; 124 int numPassed = 0; 125 126 void threadFn() 127 { 128 synchronized( synInfo ) 129 { 130 ++numReady; 131 } 132 barrier.wait(); 133 synchronized( synInfo ) 134 { 135 ++numPassed; 136 } 137 } 138 139 auto group = new ThreadGroup; 140 141 for( int i = 0; i < numThreads; ++i ) 142 { 143 group.create( &threadFn ); 144 } 145 group.joinAll(); 146 assert( numReady == numThreads && numPassed == numThreads ); 147 } 148 }