132
|
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 * Authors: 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 }
|