1 /**
2  * The barrier module provides a primitive for synchronizing the progress of
3  * a group of threads.
4  *
5  * Copyright: Copyright Sean Kelly 2005 - 2009.
6  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Authors:   Sean Kelly
8  * Source:    $(DRUNTIMESRC core/sync/_barrier.d)
9  */
10 
11 /*          Copyright Sean Kelly 2005 - 2009.
12  * Distributed under the Boost Software License, Version 1.0.
13  *    (See accompanying file LICENSE or copy at
14  *          http://www.boost.org/LICENSE_1_0.txt)
15  */
16 module core.sync.barrier;
17 
18 
19 public import core.sync.exception;
20 import core.sync.condition;
21 import core.sync.mutex;
22 
23 
24 ////////////////////////////////////////////////////////////////////////////////
25 // Barrier
26 //
27 // void wait();
28 ////////////////////////////////////////////////////////////////////////////////
29 
30 
31 /**
32  * This class represents a barrier across which threads may only travel in
33  * groups of a specific size.
34  */
35 class Barrier
36 {
37     ////////////////////////////////////////////////////////////////////////////
38     // Initialization
39     ////////////////////////////////////////////////////////////////////////////
40 
41 
42     /**
43      * Initializes a barrier object which releases threads in groups of limit
44      * in size.
45      *
46      * Params:
47      *  limit = The number of waiting threads to release in unison.
48      *
49      * Throws:
50      *  SyncError on error.
51      */
52     this( uint limit )
53     in
54     {
55         assert( limit > 0 );
56     }
57     do
58     {
59         m_lock  = new Mutex;
60         m_cond  = new Condition( m_lock );
61         m_group = 0;
62         m_limit = limit;
63         m_count = limit;
64     }
65 
66 
67     ////////////////////////////////////////////////////////////////////////////
68     // General Actions
69     ////////////////////////////////////////////////////////////////////////////
70 
71 
72     /**
73      * Wait for the pre-determined number of threads and then proceed.
74      *
75      * Throws:
76      *  SyncError on error.
77      */
78     void wait()
79     {
80         synchronized( m_lock )
81         {
82             uint group = m_group;
83 
84             if ( --m_count == 0 )
85             {
86                 m_group++;
87                 m_count = m_limit;
88                 m_cond.notifyAll();
89             }
90             while ( group == m_group )
91                 m_cond.wait();
92         }
93     }
94 
95 
96 private:
97     Mutex       m_lock;
98     Condition   m_cond;
99     uint        m_group;
100     uint        m_limit;
101     uint        m_count;
102 }
103 
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 // Unit Tests
107 ////////////////////////////////////////////////////////////////////////////////
108 
109 unittest
110 {
111     import core.thread;
112 
113     int  numThreads = 10;
114     auto barrier    = new Barrier( numThreads );
115     auto synInfo    = new Object;
116     int  numReady   = 0;
117     int  numPassed  = 0;
118 
119     void threadFn()
120     {
121         synchronized( synInfo )
122         {
123             ++numReady;
124         }
125         barrier.wait();
126         synchronized( synInfo )
127         {
128             ++numPassed;
129         }
130     }
131 
132     auto group = new ThreadGroup;
133 
134     for ( int i = 0; i < numThreads; ++i )
135     {
136         group.create( &threadFn );
137     }
138     group.joinAll();
139     assert( numReady == numThreads && numPassed == numThreads );
140 }