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
|
// $Id$
#include "Barrier_i.h"
#include "ace/Task.h"
/* We'll use a simple Task<> derivative to test our new Barrier
object.
*/
class Test : public ACE_Task<ACE_NULL_SYNCH>
{
public:
// Open the object with a few threads
int open(int _threads);
// Perform the test
int svc(void);
protected:
// The Barrier object we'll use in our tests below
Barrier barrier_;
};
/* As usual, our open() will create one or more threads where we'll do
the interesting work.
*/
int Test::open( int _threads )
{
// One thing about the barrier: You have to tell it how many
// threads it will be synching. The threads() mutator on my
// Barrier class lets you do that and hides the implementation
// details at the same time.
barrier_.threads(_threads);
// Activate the tasks as usual...
return this->activate(THR_NEW_LWP, _threads);
}
/* svc() will execute in each thread & do a few things with the
Barrier we have.
*/
int Test::svc(void)
{
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entry\n"));
// Initialize the random number generator. We'll use this to
// create sleep() times in each thread. This will help us see
// if the barrier synch is working.
ACE_RANDR_TYPE seed = ACE_OS::thr_self();
ACE_OS::srand(seed);
int delay;
// After saying hello above, sleep for a random amount of time
// from 1 to 6 seconds. That will cause the next message
// "Entering wait()" to be staggered on the output as each
// thread's sleep() returns.
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
// When executing the app you should see these messages
// staggered in an at-most 6 second window. That is, you
// won't likely see them all at once.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entering wait()\n"));
// All of the threads will now wait at this point. As each
// thread finishes the sleep() above it will join the waiters.
if( barrier_.wait() == -1 )
{
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tbarrier_.wait() failed!\n"));
return 0;
}
// When all threads have reached wait() they will give us this
// message. If you execute this, you should see all of the
// "Everybody together" messages at about the same time.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Everybody together?\n"));
// Now we do the sleep() cycle again...
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
// As before, these will trickle in over a few seconds.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Entering done()\n"));
// This time we call done() instead of wait(). done()
// actually invokes wait() but before returning here, it will
// clean up a few resources. The goal is to prevent carrying
// around objects you don't need.
if( barrier_.wait() == -1 )
{
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tbarrier_.done() failed!\n"));
return 0;
}
// Since done() invokes wait() internally, we'll see this
// message from each thread simultaneously
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Is everyone still here?\n"));
// A final sleep()
delay = ACE_OS::rand_r(seed)%5;
ACE_OS::sleep(abs(delay)+1);
// These should be randomly spaced like all of the other
// post-sleep messages.
ACE_DEBUG ((LM_INFO, "(%P|%t|%T)\tTest::svc() Chaos and anarchy for all!\n"));
return(0);
}
/* Our test application...
*/
int main(int, char**)
{
// Create the test object
Test test;
// and open it with 10 threads.
test.open(10);
// Now wait for them all to exit.
test.wait();
// Re-open the Test object with just 5 threads
test.open(5);
// and wait for them to complete also.
test.wait();
return(0);
}
|