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"
23 // The following Parent and Child classes illustrate how you might use the
24 // ACE_Strong_Bound_Ptr and ACE_Weak_Bound_Ptr together in cyclic
29 virtual ~Child_Base (void);
31 // Perform some operation.
32 virtual void do_something (void) = 0;
36 // This class should only be created on the heap. Normally it would be an
37 // abstract class, and the implementation would be elsewhere.
43 // Weak pointer to this object used to hand out new references. Must be
44 // weak since it can't own itself!
45 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> weak_self_
;
47 // The parent owns the child. When the parent is destroyed the child will
48 // be automatically deleted.
49 ACE_Strong_Bound_Ptr
<Child_Base
, ACE_Null_Mutex
> child_
;
51 // Called by the child to perform some operation.
52 void do_something (void);
54 static size_t instance_count_
;
57 // This class should only be created on the heap. Normally it would be an
58 // abstract class, and the implementation would be elsewhere.
59 struct Child
: public Child_Base
61 Child (ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent
);
62 virtual ~Child (void);
64 // Back pointer to the parent. The child does not own the parent so has no
65 // effect on its lifetime.
66 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent_
;
68 // Perform some operation. Delegates the work to the parent.
69 virtual void do_something (void);
71 static size_t instance_count_
;
74 Child_Base::~Child_Base (void)
79 size_t Parent::instance_count_
= 0;
83 child_(new Child(weak_self_
))
86 ACE_TEXT ("(%t) Creating Parent object\n")));
87 ++Parent::instance_count_
;
90 Parent::~Parent (void)
92 --Parent::instance_count_
;
94 ACE_TEXT ("(%t) Deleting Parent object\n")));
97 void Parent::do_something (void)
100 ACE_TEXT ("(%t) Parent doing something\n")));
103 size_t Child::instance_count_
= 0;
105 Child::Child (ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> parent
)
108 ACE_DEBUG ((LM_DEBUG
,
109 ACE_TEXT ("(%t) Creating Child object\n")));
110 ++Child::instance_count_
;
115 --Child::instance_count_
;
116 ACE_DEBUG ((LM_DEBUG
,
117 ACE_TEXT ("(%t) Deleting Child object\n")));
120 void Child::do_something (void)
122 ACE_DEBUG ((LM_DEBUG
,
123 ACE_TEXT ("(%t) Child doing something\n")));
125 // Using operator-> on a weak pointer will automatically create a strong
126 // pointer as a temporary. This ensures that the object exists for the
127 // lifetime of the call (although it does not check for null).
128 parent_
->do_something ();
130 // In cases where we may need to call operations on the weak pointer
131 // many times, we can reduce the overhead by explicitly converting to a
132 // strong pointer first.
133 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> strong_parent (parent_
);
135 // You can check for null to see if the parent object still exists (in this
136 // case it is not strictly necessary since the child will only exist if the
137 // parent still exists).
138 if (strong_parent
== 0)
141 for (int i
= 0; i
< 5; ++i
)
142 strong_parent
->do_something ();
145 size_t Printer::instance_count_
= 0;
147 Printer::Printer (const char *message
)
150 ACE_DEBUG ((LM_DEBUG
,
151 ACE_TEXT ("(%t) Creating Printer object\n")));
152 ++Printer::instance_count_
;
155 Printer::~Printer (void)
157 --Printer::instance_count_
;
158 ACE_DEBUG ((LM_DEBUG
,
159 ACE_TEXT ("(%t) Deleting Printer object\n")));
163 Printer::print (void)
165 ACE_DEBUG ((LM_DEBUG
,
166 ACE_TEXT ("(%t) %C\n"),
170 #if defined (ACE_HAS_THREADS)
173 * @class Method_Request_print
175 * @brief Reification of the <print> method.
177 class Method_Request_print
: public ACE_Method_Request
180 explicit Method_Request_print (Printer_var
&printer
);
181 virtual ~Method_Request_print (void);
183 /// This is the entry point into the Active Object method.
184 virtual int call (void);
187 Printer_var printer_
;
190 Method_Request_print::Method_Request_print (Printer_var
&printer
)
193 ACE_DEBUG ((LM_DEBUG
,
194 ACE_TEXT ("(%t) Method_Request_print created\n")));
197 Method_Request_print::~Method_Request_print (void)
199 ACE_DEBUG ((LM_DEBUG
,
200 ACE_TEXT ("(%t) Method_Request_print will be deleted.\n")));
204 Method_Request_print::call (void)
206 // Dispatch the Servant's operation and store the result into the
208 Printer_var temp
= printer_
;
216 * @class Method_Request_end
218 * @brief Reification of the <end> method.
220 class Method_Request_end
: public ACE_Method_Request
223 Method_Request_end (Scheduler
*new_Prime_Scheduler
);
224 virtual ~Method_Request_end (void);
225 virtual int call (void);
228 Scheduler
*scheduler_
;
231 Method_Request_end::Method_Request_end (Scheduler
*scheduler
)
232 : scheduler_ (scheduler
)
236 Method_Request_end::~Method_Request_end (void)
241 Method_Request_end::call (void)
243 // Shut down the scheduler by deactivating the activation queue's
244 // underlying message queue - should pop all worker threads off their
245 // wait and they'll exit.
246 this->scheduler_
->msg_queue ()->deactivate ();
251 // Associates the activation queue with this task's message queue,
252 // allowing easy access to the message queue for shutting it down
253 // when it's time to stop this object's service threads.
254 Scheduler::Scheduler (void)
255 : activation_queue_ (msg_queue ())
257 ACE_DEBUG ((LM_DEBUG
,
258 ACE_TEXT ("(%t) Scheduler created\n")));
263 Scheduler::~Scheduler (void)
265 ACE_DEBUG ((LM_DEBUG
,
266 ACE_TEXT ("(%t) Scheduler will be destroyed\n")));
272 Scheduler::open (void *)
274 ACE_DEBUG ((LM_DEBUG
,
275 ACE_TEXT ("(%t) Scheduler open\n")));
276 // Become an Active Object.
278 return this->activate (THR_BOUND
| THR_JOINABLE
, num_threads
);
284 Scheduler::close (u_long
)
286 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("(%t) rundown\n")));
293 Scheduler::svc (void)
297 // Dequeue the next method request (we use an strong pointer in
298 // case an exception is thrown in the <call>).
299 ACE_Strong_Bound_Ptr
<ACE_Method_Request
, ACE_Null_Mutex
> mo (this->activation_queue_
.dequeue ());
302 ACE_DEBUG ((LM_DEBUG
,
303 ACE_TEXT ("(%t) activation queue shut down\n")));
307 ACE_DEBUG ((LM_DEBUG
,
308 ACE_TEXT ("(%t) calling method request\n")));
310 if (mo
->call () == -1)
313 // Destructor automatically deletes it.
320 Scheduler::end (void)
322 this->activation_queue_
.enqueue (new Method_Request_end (this));
325 // Here's where the work takes place.
328 Scheduler::print (Printer_var
&printer
)
330 this->activation_queue_
.enqueue
331 (new Method_Request_print (printer
));
334 // Total number of loops.
335 static int n_loops
= 10;
337 #endif /* ACE_HAS_THREADS */
340 run_main (int, ACE_TCHAR
*[])
342 ACE_START_TEST (ACE_TEXT ("Bound_Ptr_Test"));
345 // =========================================================================
346 // The following test uses the ACE_Strong_Bound_Ptr in a single
347 // thread of control, hence we use the ACE_Null_Mutex
349 ACE_DEBUG ((LM_DEBUG
,
350 ACE_TEXT ("(%t) performing synchronous test...\n")));
353 ACE_NEW_RETURN (parent1
,
356 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p8
;
358 // Must get the pointer from the parent object's weak_self_ member.
359 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p(parent1
->weak_self_
);
360 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p1(p
);
361 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p2(p
);
362 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p3(p
);
363 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p4(p
);
364 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p5
= p2
;
365 ACE_Strong_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p6
= p3
;
366 ACE_Weak_Bound_Ptr
<Parent
, ACE_Null_Mutex
> p7(p1
);
368 p
->child_
->do_something ();
370 ACE_DEBUG ((LM_DEBUG
,
371 ACE_TEXT ("(%t) Parent instance count is %d, expecting 0\n"),
372 Parent::instance_count_
));
373 if (Parent::instance_count_
!= 0)
375 ACE_ERROR_RETURN ((LM_ERROR
,
376 ACE_TEXT ("(%t) parent instance count not 0...\n")),
379 ACE_DEBUG ((LM_DEBUG
,
380 ACE_TEXT ("(%t) Child instance count is %d, expecting 0\n"),
381 Child::instance_count_
));
382 if (Child::instance_count_
!= 0)
384 ACE_ERROR_RETURN ((LM_ERROR
,
385 ACE_TEXT ("(%t) child instance count not 0...\n")),
388 // Weak pointer should now be set to null.
391 ACE_ERROR_RETURN ((LM_ERROR
,
392 ACE_TEXT ("(%t) p8 not nill...\n")),
396 Printer
*printer1
= 0;
397 ACE_NEW_RETURN (printer1
,
398 Printer ("I am printer 1"),
400 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r9
;
402 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r(printer1
);
403 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r1(r
);
404 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r2(r
);
405 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r3(r
);
406 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r4(r
);
407 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r5
= r2
;
408 ACE_Strong_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r6
= r1
;
409 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r7(r1
);
410 ACE_Weak_Bound_Ptr
<Printer
, ACE_Null_Mutex
> r8
= r2
;
414 ACE_DEBUG ((LM_DEBUG
,
415 ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
416 Printer::instance_count_
));
417 if (Printer::instance_count_
!= 0)
419 ACE_ERROR_RETURN ((LM_ERROR
,
420 ACE_TEXT ("(%t) Printer instance count not 0...\n")),
423 // Weak pointer should now be set to null.
426 ACE_ERROR_RETURN ((LM_ERROR
,
427 ACE_TEXT ("(%t) r9 not nill...\n")),
431 #if defined (ACE_HAS_THREADS)
433 // =========================================================================
434 // The following test uses the ACE_Strong_Bound_Ptr in multiple
435 // threads of control.
437 ACE_DEBUG ((LM_DEBUG
,
438 ACE_TEXT ("(%t) performing asynchronous test...\n")));
440 Scheduler
*scheduler_ptr
= 0;
442 // Create active objects..
443 ACE_NEW_RETURN (scheduler_ptr
,
447 ACE_Strong_Bound_Ptr
<Scheduler
, ACE_Null_Mutex
> scheduler(scheduler_ptr
);
449 if (scheduler
->open () == -1)
451 ACE_ERROR_RETURN ((LM_ERROR
,
452 ACE_TEXT ("(%t) Scheduler open failed...\n")),
457 Printer
*printer2
= 0;
458 ACE_NEW_RETURN (printer2
,
459 Printer ("I am printer 2"),
462 #if !defined (ACE_HAS_CPP11)
463 // Ownership is transferred from the auto_ptr to the strong pointer.
464 auto_ptr
<Printer
> a (printer2
);
467 Printer_var
r (printer2
);
468 #endif /* !ACE_HAS_CPP11 */
470 for (int i
= 0; i
< n_loops
; i
++)
471 // Spawn off the methods, which run in a separate thread as
472 // active object invocations.
473 scheduler
->print (r
);
476 // Close things down.
481 ACE_DEBUG ((LM_DEBUG
,
482 ACE_TEXT ("(%t) Printer instance count is %d, expecting 0\n"),
483 Printer::instance_count_
));
484 if (Printer::instance_count_
!= 0)
487 #endif /* ACE_HAS_THREADS */