summaryrefslogtreecommitdiff
path: root/docs/tutorials/017/page04.html
blob: 88ff60be5656d4226f984fe7e5ad48c8fc2cd7ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 017</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 017</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>Using the ACE_Barrier synch object</FONT></B></CENTER>

<P>
<HR WIDTH="100%">
The Barrier implementation is quite simple.  The threads() mutator
took a couple of tries to get right.  In particular, be sure you know
when to apply the _wait paramter and when not to!  In fact, the
requirement that only the "owning" thread can change the thread count
is rather limiting.  A more appropriate solution would allow any
thread to safely change the count but that would require more complex
locking that is just a bit more than what I wanted to present here.
<HR>
<PRE>

<font color=red>// $Id$</font>

<font color=blue>#include</font> "<font color=green>Barrier_i.h</font>"

<font color=red>/* Initialize the threads_ count to zero and the barrier_ pointer to a
   safe value.  At the same time, we remember the thread that created
   us so that we can allow it to change the thread count.
*/</font>
<font color=#008888>Barrier::Barrier</font>(void)
   : threads_(0)
    ,barrier_(0)
    ,new_barrier_(0)
{
    owner_ = <font color=#008888>ACE_OS::thr_self</font>();
}

<font color=red>/* Ensure that barrier_ get's deleted so that we don't have a memory leak.
 */</font>
<font color=#008888>Barrier::~Barrier</font>(void)
{
    delete barrier_;
}

void <font color=#008888>Barrier::owner</font>( ACE_thread_t _owner )
{
    owner_ = _owner;
}

<font color=red>// Report on the number of threads.</font>
u_int <font color=#008888>Barrier::threads</font>(void)
{
    return threads_.value();
}

<font color=red>/* Allow the owning thread to (re)set the number of threads.
   make_barrier() is called because it will wait() if we were already
   configured.  Typical usage would be for the worker threads to
   wait() while the primary (eg -- owner) thread adjusts the thread
   count.

   For instance:
       In the worker threads:
           if( myBarrier.threads() != current_thread_count )
               myBarrier.wait();

       In the primary thread:
           if( myBarrier.threads() != current_thread_count )
               myBarrier.threads( current_thread_count, 1 );
 */</font>
int <font color=#008888>Barrier::threads</font>( u_int _threads, int _wait )
{
    if( ! <font color=#008888>ACE_OS::thr_equal</font>(ACE_OS::thr_self(), owner_) )
    {
        return -1;
    }

    threads_ = _threads;
    
    return make_barrier(_wait);
}

<font color=red>/* Wait for all threads to synch if the thread count is valid.  Note
   that barrier_ will be 0 if the threads() mutator has not been
   invoked.
*/</font>
int <font color=#008888>Barrier::wait</font>(void)
{
    if( ! barrier_ )
    {
        return -1;
    }

        <font color=red>// If the threads() mutator has been used, new_barrier_ will</font>
        <font color=red>// point to a new ACE_Barrier instance.  We'll use a</font>
        <font color=red>// traditional double-check here to move that new object into</font>
        <font color=red>// place and cleanup the old one.</font>
    if( new_barrier_ )
    {
            <font color=red>// mutex so that only one thread can do this part.</font>
        ACE_Guard&lt;ACE_Mutex> mutex(barrier_mutex_);
 
            <font color=red>// We only want the first thread to plug in the new barrier...</font>
        if( new_barrier_ )
        {
                <font color=red>// out with the old and in with the new.</font>
            delete barrier_;
            barrier_ = new_barrier_;
            new_barrier_ = 0;
        }
    }

    return barrier_->wait();
}

<font color=red>/* Wait for all threads to synch.  As each thread passes wait(), it
   will decrement our thread counter.  (That is why we had to make
   threads_ an atomic op.)  When the last thread decrements the
   counter it will also delete the ACE_Barrier & free up a little
   memory.
*/</font>
int <font color=#008888>Barrier::done</font>(void)
{
    if( this->wait() == -1 )
    {
        return -1;
    }

    --threads_;

    if( ! threads_.value() )
    {
        delete barrier_;
        barrier_ = 0;
    }

    return 0;
}

<font color=red>/* This will build the actual barrier.  I broke this code out of the
   threads() mutator in case it might be useful elsewhere.
   If a barrier already exists, we will wait for all threads before
   creating a new one.  This trait is what allows the threads mutator
   to be used as shown above.
 */</font>
int <font color=#008888>Barrier::make_barrier</font>( int _wait )
{
        <font color=red>// Ensure we have a valid thread count.</font>
    if( ! threads_.value() )
    {
        return -1;
    }

        <font color=red>// If a barrier already exists, we'll arrange for it to be</font>
        <font color=red>// replaced through the wait() method above.</font>
    if( barrier_ )
    {
            <font color=red>// Create the new barrier that wait() will install for us.</font>
        ACE_NEW_RETURN(new_barrier_,ACE_Barrier(threads_.value()),-1);

            <font color=red>// Wait for our siblings to synch before continuing</font>
        if( _wait )
        {
            barrier_->wait();
        }
    }
    else
    {
            <font color=red>// Create the initial barrier.</font>
        ACE_NEW_RETURN(barrier_,ACE_Barrier(threads_.value()),-1);
    }

    return 0;
}
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>