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 }