1 //=============================================================================
3 * @file Bound_Ptr_Test.cpp
5 * This example tests the <ACE_Strong_Bound_Ptr> and
6 * <ACE_Weak_Bound_Ptr> and illustrates how they may be dispersed
7 * between multiple threads using an implementation of the Active
8 * Object pattern, which is available in the POSA2 book
9 * <http://www.dre.vanderbilt.edu/~schmidt/POSA>.
11 * @author Christopher Kohlhoff <chris@kohlhoff.com>
13 //=============================================================================
15 #include "test_config.h"
16 #include "ace/Null_Mutex.h"
17 #include "ace/Method_Request.h"
18 #include "Bound_Ptr_Test.h"
21 // The following Parent and Child classes illustrate how you might use the
22 // ACE_Strong_Bound_Ptr and ACE_Weak_Bound_Ptr together in cyclic
26 virtual ~Child_Base ();
28 // Perform some operation.
29 virtual void do_something () = 0;
32 // This class should only be created on the heap. Normally it would be an
33 // abstract class, and the implementation would be elsewhere.
39 // Weak pointer to this object used to hand out new references. Must be
40 // weak since it can't own itself!
41 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> weak_self_
;
43 // The parent owns the child. When the parent is destroyed the child will
44 // be automatically deleted.
45 ACE_Strong_Bound_Ptr
<Child_Base
, ACE_Null_Mutex
> child_
;
47 // Called by the child to perform some operation.
50 static size_t instance_count_
;
53 // This class should only be created on the heap. Normally it would be an
54 // abstract class, and the implementation would be elsewhere.
55 struct Child
: public Child_Base
57 Child (ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent
);
60 // Back pointer to the parent. The child does not own the parent so has no
61 // effect on its lifetime.
62 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent_
;
64 // Perform some operation. Delegates the work to the parent.
65 void do_something () override
;
67 static size_t instance_count_
;
70 Child_Base::~Child_Base ()
74 size_t Parent::instance_count_
= 0;
78 child_(new Child(weak_self_
))
81 ACE_TEXT ("(%t) Creating Parent object\n")));
82 ++Parent::instance_count_
;
87 --Parent::instance_count_
;
89 ACE_TEXT ("(%t) Deleting Parent object\n")));
92 void Parent::do_something ()
95 ACE_TEXT ("(%t) Parent doing something\n")));
98 size_t Child::instance_count_
= 0;
100 Child::Child (ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent
)
103 ACE_DEBUG ((LM_DEBUG
,
104 ACE_TEXT ("(%t) Creating Child object\n")));
105 ++Child::instance_count_
;
110 --Child::instance_count_
;
111 ACE_DEBUG ((LM_DEBUG
,
112 ACE_TEXT ("(%t) Deleting Child object\n")));
115 void Child::do_something ()
117 ACE_DEBUG ((LM_DEBUG
,
118 ACE_TEXT ("(%t) Child doing something\n")));
120 // Using operator-> on a weak pointer will automatically create a strong
121 // pointer as a temporary. This ensures that the object exists for the
122 // lifetime of the call (although it does not check for null).
123 parent_
->do_something ();
125 // In cases where we may need to call operations on the weak pointer
126 // many times, we can reduce the overhead by explicitly converting to a
127 // strong pointer first.
128 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> strong_parent (parent_
);
130 // You can check for null to see if the parent object still exists (in this
131 // case it is not strictly necessary since the child will only exist if the
132 // parent still exists).
133 if (strong_parent
== 0)
136 for (int i
= 0; i
< 5; ++i
)
137 strong_parent
->do_something ();
140 size_t Printer::instance_count_
= 0;
142 Printer::Printer (const char *message
)
145 ACE_DEBUG ((LM_DEBUG
,
146 ACE_TEXT ("(%t) Creating Printer object\n")));
147 ++Printer::instance_count_
;
152 --Printer::instance_count_
;
153 ACE_DEBUG ((LM_DEBUG
,
154 ACE_TEXT ("(%t) Deleting Printer object\n")));
160 ACE_DEBUG ((LM_DEBUG
,
161 ACE_TEXT ("(%t) %C\n"),
165 #if defined (ACE_HAS_THREADS)
168 * @class Method_Request_print
170 * @brief Reification of the <print> method.
172 class Method_Request_print
: public ACE_Method_Request
175 explicit Method_Request_print (Printer_var
&printer
);
176 ~Method_Request_print () override
;
178 /// This is the entry point into the Active Object method.
179 int call () override
;
182 Printer_var printer_
;
185 Method_Request_print::Method_Request_print (Printer_var
&printer
)
188 ACE_DEBUG ((LM_DEBUG
,
189 ACE_TEXT ("(%t) Method_Request_print created\n")));
192 Method_Request_print::~Method_Request_print ()
194 ACE_DEBUG ((LM_DEBUG
,
195 ACE_TEXT ("(%t) Method_Request_print will be deleted.\n")));
199 Method_Request_print::call ()
201 // Dispatch the Servant's operation and store the result into the
203 Printer_var temp
= printer_
;
211 * @class Method_Request_end
213 * @brief Reification of the <end> method.
215 class Method_Request_end
: public ACE_Method_Request
218 Method_Request_end (Scheduler
*new_Prime_Scheduler
);
219 ~Method_Request_end () override
;
220 int call () override
;
223 Scheduler
*scheduler_
;
226 Method_Request_end::Method_Request_end (Scheduler
*scheduler
)
227 : scheduler_ (scheduler
)
231 Method_Request_end::~Method_Request_end ()
236 Method_Request_end::call ()
238 // Shut down the scheduler by deactivating the activation queue's
239 // underlying message queue - should pop all worker threads off their
240 // wait and they'll exit.
241 this->scheduler_
->msg_queue ()->deactivate ();
246 // Associates the activation queue with this task's message queue,
247 // allowing easy access to the message queue for shutting it down
248 // when it's time to stop this object's service threads.
249 Scheduler::Scheduler ()
250 : activation_queue_ (msg_queue ())
252 ACE_DEBUG ((LM_DEBUG
,
253 ACE_TEXT ("(%t) Scheduler created\n")));
258 Scheduler::~Scheduler ()
260 ACE_DEBUG ((LM_DEBUG
,
261 ACE_TEXT ("(%t) Scheduler will be destroyed\n")));
267 Scheduler::open (void *)
269 ACE_DEBUG ((LM_DEBUG
,
270 ACE_TEXT ("(%t) Scheduler open\n")));
271 // Become an Active Object.
273 return this->activate (THR_BOUND
| THR_JOINABLE
, num_threads
);
279 Scheduler::close (u_long
)
281 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("(%t) rundown\n")));
292 // Dequeue the next method request (we use an strong pointer in
293 // case an exception is thrown in the <call>).
294 ACE_Strong_Bound_Ptr
<ACE_Method_Request
, ACE_Null_Mutex
> mo (this->activation_queue_
.dequeue ());
297 ACE_DEBUG ((LM_DEBUG
,
298 ACE_TEXT ("(%t) activation queue shut down\n")));
302 ACE_DEBUG ((LM_DEBUG
,
303 ACE_TEXT ("(%t) calling method request\n")));
305 if (mo
->call () == -1)
308 // Destructor automatically deletes it.
317 this->activation_queue_
.enqueue (new Method_Request_end (this));
320 // Here's where the work takes place.
323 Scheduler::print (Printer_var
&printer
)
325 this->activation_queue_
.enqueue
326 (new Method_Request_print (printer
));
329 // Total number of loops.
330 static int n_loops
= 10;
332 #endif /* ACE_HAS_THREADS */
335 run_main (int, ACE_TCHAR
*[])
337 ACE_START_TEST (ACE_TEXT ("Bound_Ptr_Test"));
340 // =========================================================================
341 // The following test uses the ACE_Strong_Bound_Ptr in a single
342 // thread of control, hence we use the ACE_Null_Mutex
344 ACE_DEBUG ((LM_DEBUG
,
345 ACE_TEXT ("(%t) performing synchronous test...\n")));
348 ACE_NEW_RETURN (parent1
,
351 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p8
;
353 // Must get the pointer from the parent object's weak_self_ member.
354 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p(parent1
->weak_self_
);
355 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p1(p
);
356 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p2(p
);
357 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p3(p
);
358 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p4(p
);
359 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p5
= p2
;
360 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p6
= p3
;
361 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p7(p1
);
363 p
->child_
->do_something ();
365 ACE_DEBUG ((LM_DEBUG
,
366 ACE_TEXT ("(%t) Parent instance count is %d, expecting 0\n"),
367 Parent::instance_count_
));
368 if (Parent::instance_count_
!= 0)
370 ACE_ERROR_RETURN ((LM_ERROR
,
371 ACE_TEXT ("(%t) parent instance count not 0...\n")),
374 ACE_DEBUG ((LM_DEBUG
,
375 ACE_TEXT ("(%t) Child instance count is %d, expecting 0\n"),
376 Child::instance_count_
));
377 if (Child::instance_count_
!= 0)
379 ACE_ERROR_RETURN ((LM_ERROR
,
380 ACE_TEXT ("(%t) child instance count not 0...\n")),
383 // Weak pointer should now be set to null.
386 ACE_ERROR_RETURN ((LM_ERROR
,
387 ACE_TEXT ("(%t) p8 not nill...\n")),
391 Printer
*printer1
= 0;
392 ACE_NEW_RETURN (printer1
,
393 Printer ("I am printer 1"),
395 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r9
;
397 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r(printer1
);
398 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r1(r
);
399 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r2(r
);
400 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r3(r
);
401 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r4(r
);
402 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r5
= r2
;
403 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r6
= r1
;
404 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r7(r1
);
405 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r8
= r2
;
409 ACE_DEBUG ((LM_DEBUG
,
410 ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
411 Printer::instance_count_
));
412 if (Printer::instance_count_
!= 0)
414 ACE_ERROR_RETURN ((LM_ERROR
,
415 ACE_TEXT ("(%t) Printer instance count not 0...\n")),
418 // Weak pointer should now be set to null.
421 ACE_ERROR_RETURN ((LM_ERROR
,
422 ACE_TEXT ("(%t) r9 not nill...\n")),
426 #if defined (ACE_HAS_THREADS)
428 // =========================================================================
429 // The following test uses the ACE_Strong_Bound_Ptr in multiple
430 // threads of control.
432 ACE_DEBUG ((LM_DEBUG
,
433 ACE_TEXT ("(%t) performing asynchronous test...\n")));
435 Scheduler
*scheduler_ptr
= 0;
437 // Create active objects..
438 ACE_NEW_RETURN (scheduler_ptr
,
442 ACE_Strong_Bound_Ptr
<Scheduler
, ACE_Null_Mutex
> scheduler(scheduler_ptr
);
444 if (scheduler
->open () == -1)
446 ACE_ERROR_RETURN ((LM_ERROR
,
447 ACE_TEXT ("(%t) Scheduler open failed...\n")),
452 Printer
*printer2
= 0;
453 ACE_NEW_RETURN (printer2
,
454 Printer ("I am printer 2"),
457 Printer_var
r (printer2
);
459 for (int i
= 0; i
< n_loops
; i
++)
460 // Spawn off the methods, which run in a separate thread as
461 // active object invocations.
462 scheduler
->print (r
);
465 // Close things down.
470 ACE_DEBUG ((LM_DEBUG
,
471 ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
472 Printer::instance_count_
));
473 if (Printer::instance_count_
!= 0)
476 #endif /* ACE_HAS_THREADS */