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 */
16module core.sync.barrier;
17
18
19public import core.sync.exception;
20import core.sync.condition;
21import 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 */
35class 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
96private:
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
109unittest
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}
141