Doxygen changes
[ACE_TAO.git] / ACE / tests / Bound_Ptr_Test.cpp
blob9b663caafdbf117b67a5bdbc707e3b3dcfe9f32c
1 //=============================================================================
2 /**
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"
19 #include "ace/Task.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
25 // relationships.
27 struct Child_Base
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.
38 struct Parent
40 Parent (void);
41 ~Parent (void);
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;
81 Parent::Parent (void)
82 : weak_self_(this),
83 child_(new Child(weak_self_))
85 ACE_DEBUG ((LM_DEBUG,
86 ACE_TEXT ("(%t) Creating Parent object\n")));
87 ++Parent::instance_count_;
90 Parent::~Parent (void)
92 --Parent::instance_count_;
93 ACE_DEBUG ((LM_DEBUG,
94 ACE_TEXT ("(%t) Deleting Parent object\n")));
97 void Parent::do_something (void)
99 ACE_DEBUG ((LM_DEBUG,
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)
106 : parent_(parent)
108 ACE_DEBUG ((LM_DEBUG,
109 ACE_TEXT ("(%t) Creating Child object\n")));
110 ++Child::instance_count_;
113 Child::~Child (void)
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)
139 return;
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)
148 : message_ (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")));
162 void
163 Printer::print (void)
165 ACE_DEBUG ((LM_DEBUG,
166 ACE_TEXT ("(%t) %C\n"),
167 this->message_));
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
179 public:
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);
186 private:
187 Printer_var printer_;
190 Method_Request_print::Method_Request_print (Printer_var &printer)
191 : printer_ (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
207 // Future.
208 Printer_var temp = printer_;
210 temp->print ();
212 return 0;
216 * @class Method_Request_end
218 * @brief Reification of the <end> method.
220 class Method_Request_end : public ACE_Method_Request
222 public:
223 Method_Request_end (Scheduler *new_Prime_Scheduler);
224 virtual ~Method_Request_end (void);
225 virtual int call (void);
227 private:
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 ();
247 return -1;
250 // Constructor
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")));
261 // Destructor
263 Scheduler::~Scheduler (void)
265 ACE_DEBUG ((LM_DEBUG,
266 ACE_TEXT ("(%t) Scheduler will be destroyed\n")));
269 // open
272 Scheduler::open (void *)
274 ACE_DEBUG ((LM_DEBUG,
275 ACE_TEXT ("(%t) Scheduler open\n")));
276 // Become an Active Object.
277 int num_threads = 3;
278 return this->activate (THR_BOUND | THR_JOINABLE, num_threads);
281 // close
284 Scheduler::close (u_long)
286 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) rundown\n")));
287 return 0;
290 // Service..
293 Scheduler::svc (void)
295 for (;;)
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 ());
300 if (mo == 0)
302 ACE_DEBUG ((LM_DEBUG,
303 ACE_TEXT ("(%t) activation queue shut down\n")));
304 break;
307 ACE_DEBUG ((LM_DEBUG,
308 ACE_TEXT ("(%t) calling method request\n")));
309 // Call it.
310 if (mo->call () == -1)
311 break;
313 // Destructor automatically deletes it.
316 return 0;
319 void
320 Scheduler::end (void)
322 this->activation_queue_.enqueue (new Method_Request_end (this));
325 // Here's where the work takes place.
327 void
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")));
352 Parent *parent1 = 0;
353 ACE_NEW_RETURN (parent1,
354 Parent,
355 -1);
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);
367 p8 = p2;
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")),
377 -1);
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")),
386 -1);
388 // Weak pointer should now be set to null.
389 if(!p8.null ())
391 ACE_ERROR_RETURN ((LM_ERROR,
392 ACE_TEXT ("(%t) p8 not nill...\n")),
393 -1);
396 Printer *printer1 = 0;
397 ACE_NEW_RETURN (printer1,
398 Printer ("I am printer 1"),
399 -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;
411 r9 = r3;
412 r9->print ();
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")),
421 -1);
423 // Weak pointer should now be set to null.
424 if (!r9.null ())
426 ACE_ERROR_RETURN ((LM_ERROR,
427 ACE_TEXT ("(%t) r9 not nill...\n")),
428 -1);
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,
444 Scheduler (),
445 -1);
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")),
453 -1);
457 Printer *printer2 = 0;
458 ACE_NEW_RETURN (printer2,
459 Printer ("I am printer 2"),
460 -1);
462 #if !defined (ACE_HAS_CPP11)
463 // Ownership is transferred from the auto_ptr to the strong pointer.
464 auto_ptr<Printer> a (printer2);
465 Printer_var r (a);
466 #else
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.
477 scheduler->end ();
479 scheduler->wait ();
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)
485 return -1;
487 #endif /* ACE_HAS_THREADS */
488 ACE_END_TEST;
490 return 0;