summaryrefslogtreecommitdiff
path: root/docs/tutorials/016/page04.html
blob: c9cc4dc6b4b633ce6919791932f2d303afacdb8f (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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="Author" CONTENT="James CE Johnson">
   <TITLE>ACE Tutorial 016</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

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

<CENTER><B><FONT SIZE=+2>Making ACE_Condition easier to use</FONT></B></CENTER>

<P>
<HR WIDTH="100%">
We finally get to the main() application.  I create a simple Task
derivative that will serve as a baseclass for other objects that test
specific functions of the Condition class.  Notice how easy it is to
integrate a Condition into the application without keeping track of
three related member variables.
<HR>
<PRE>

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

<font color=blue>#include</font> "<font color=green>Condition_i.h</font>"
<font color=blue>#include</font> "<A HREF="../../../ace/Task.h">ace/Task.h</A>"

<font color=red>/* In order to test our Condition we'll derive from ACE_Task&lt;> so that
   we can have several threads accessing the condition variable
   together.
 */</font>
class Test : public ACE_Task&lt;ACE_NULL_SYNCH>
{
public:
     <font color=red>// Construct the condition variable with an initial value.</font>
    Test( int _max_threads, <font color=#008888>Condition::value_t</font> _value );
    ~Test(void);

     <font color=red>// Open the Task with enough threads to make a useful test.</font>
    int open(void);
    
protected:
     <font color=red>// Each thread will do work on the Condition.</font>
    int svc(void);

     <font color=red>// Override this method to modify the Condition in some way.</font>
    virtual void modify(void) = 0;

     <font color=red>// Override this to test the Condition in some way.</font>
    virtual void test(void) = 0;

     <font color=red>// How many threads to use in the test.  This is also used in the</font>
     <font color=red>// modify() and test() methods of the derivatives.</font>
    int max_threads_;

     <font color=red>// We want to sleep for a random amount of time to simulate</font>
     <font color=red>// work.  The seed is necessary for proper random number generation.</font>
    ACE_RANDR_TYPE seed_;

     <font color=red>// This is the actual condition variable set.</font>
    Condition condition_;
};

<font color=red>// Initialize the condition variable.</font>
<font color=#008888>Test::Test</font>( int _max_threads, Condition::value_t _value )
        : max_threads_(_max_threads), condition_(_value)
{
    ;
}

<font color=#008888>Test::~Test</font>(void)
{
    ;
}

<font color=red>// Seed the random number generator and start the threads.</font>
int <font color=#008888>Test::open</font>(void)
{
    seed_ = <font color=#008888>ACE_OS::gettimeofday</font>().usec();
    
    <font color=#008888>ACE_OS::srand</font>( seed_ );
            
    return this->activate(THR_NEW_LWP, max_threads_);
}

<font color=red>/* Each thread will modify the condition variable in some way and then 
   wait for the condition to be satisfied.  The derived classes
   overload modify() and test() to implement a specific test of the
   Condition class.
 */</font>
int <font color=#008888>Test::svc</font>(void)
{
        <font color=red>// Take a moment before we modify the condition.  This will</font>
        <font color=red>// cause test() in other threads to delay a bit.</font>
    int stime = <font color=#008888>ACE_OS::rand_r</font>( seed_ ) % 5;
    <font color=#008888>ACE_OS::sleep</font>(abs(stime)+2);
    
    ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() befor modify, condition_ is:  %d\n</font>", (int)condition_ ));

     <font color=red>// Change the condition variable's value</font>
    modify();
    
    ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() after modify, condition_ is:  %d\n</font>", (int)condition_ ));

     <font color=red>// Test for the condition we want</font>
    test();
            
    ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t|%T)\<font color=#008888>tTest::svc</font>() leaving.\n</font>" ));
    
    return(0);
}

<font color=red>/* Test <font color=#008888>Condition::operator</font>!=()
   The task's svc() method will increment the condition variable and
   then wait until the variable's value reaches max_threads_.
 */</font>
class Test_ne : public Test
{
public:
     <font color=red>// Initialize the condition variable to zero since we're counting up.</font>
    Test_ne( int _max_threads )
            : Test(_max_threads,0)
        {
            ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ != %d\n</font>", max_threads_));
        }

     <font color=red>// Increment the variable</font>
    void modify(void)
        {
            ++condition_;
        }

     <font color=red>// Wait until it equals max_threads_</font>
    void test(void)
        {
            condition_ != max_threads_;
        }
};

<font color=red>/* Test <font color=#008888>Condition::operator</font>>=()
   Each svc() method will decrement the condition variable and wait
   until it is less than max_threads_.  To do this correctly, we have
   to be careful where we start the condition variable.
 */</font>
class Test_ge : public Test
{
public:
     <font color=red>// For max_threads_ == 5, we will start the condition variable at </font>
     <font color=red>// the value 9.  When the "<font color=green>last</font>" thread decrements it, the value</font>
     <font color=red>// will be 4 which satisfies the condition.</font>
    Test_ge( int _max_threads )
            : Test(_max_threads,_max_threads*2-1)
        {
            ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ >= %d\n</font>", max_threads_));
        }

     <font color=red>// Decrement by one...</font>
    void modify(void)
        {
            --condition_;
        }

     <font color=red>// while( value >= max_threads_ ) wait();</font>
    void test(void)
        {
            condition_ >= max_threads_;
        }
};

<font color=red>/* Test <font color=#008888>Condition::operator</font>&lt;=()
   This time we will increment the condition until it is greater than
   max_threads_.  Again, we have to be careful where we start the
   value and how we increment.
 */</font>
class Test_le : public Test
{
public:
     <font color=red>// I'm starting the value at 1 so that if we increment by one in</font>
     <font color=red>// each thread, the "<font color=green>last</font>" thread (of 5) will set the value to</font>
     <font color=red>// 6.  Since I actually increment by 2, we could start somewhat lower.</font>
    Test_le( int _max_threads )
            : Test( _max_threads, 1 )
        {
            ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ &lt;= %d\n</font>", max_threads_));
        }

     <font color=red>// Try out <font color=#008888>Condition::operator</font>+=(int)</font>
     <font color=red>// This will cause the third thread to satisfy the condition.</font>
    void modify(void)
        {
            condition_ += 2;
        }

     <font color=red>// while( value &lt;= max_threads_ ) wait();</font>
    void test(void)
        {
            condition_ &lt;= max_threads_;
        }
};

<font color=red>/* For our final test, we'll go after <font color=#008888>Condition::operator</font>=(Condition::Compare)
   By deriving from <font color=#008888>Condition::Compare</font> we can perform any arbitrary
   test on the value of the condition variable.
 */</font>
class Test_fo : public Test
{
public:
     <font color=red>// We'll be using operator*=(int) to increment the condition</font>
     <font color=red>// variable, so we need to start with a non-zero value.</font>
    Test_fo( int _max_threads )
            : Test( _max_threads, 1 )
        {
            ACE_DEBUG ((LM_INFO, "<font color=green>\n(%P|%t|%T)\tTesting condition_ == FunctionObject\n</font>" ));
        }

     <font color=red>// Double the value for each thread that we have.</font>
    void modify(void)
        {
            condition_ *= 2;
        }

     <font color=red>/* Derive our CompareFunction and provide the operator() that
        performs our test.  In this case, we'll compare the value to
        the number 32.
      */</font>
    class CompareFunction : public <font color=#008888>Condition::Compare</font>
    {
    public:
         <font color=red>// When this returns non-zero, the condition test operator</font>
         <font color=red>// will unblock in each thread.</font>
         <font color=red>// Note that 32 was chosen because 2**5 == 32.  That is, the</font>
         <font color=red>// fifth thread will modify() the value to 32.</font>
        int operator() ( <font color=#008888>Condition::value_t</font> _value )
            {
                return _value == 32;
            }
    };

     <font color=red>// Create the CompareFunction and wait for the condition variable </font>
     <font color=red>// to reach the state we want.</font>
    void test(void)
        {
            CompareFunction compare;
            condition_ == compare;
        }
};

<font color=red>/* In main() we just instantiate each of the four test objects that we 
   created.  After open()ing each, we wait() for it's threads to exit.
 */</font>
int main(int, char **)
{
    Test_ne test_ne(5);
    test_ne.open();
    test_ne.wait();
    
    Test_ge test_ge(5);
    test_ge.open();
    test_ge.wait();
    
    Test_le test_le(5);
    test_le.open();
    test_le.wait();
    
    Test_fo test_fo(5);
    test_fo.open();
    test_fo.wait();
    
    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>