Use =default for skeleton copy constructor
[ACE_TAO.git] / ACE / tests / Future_Set_Test.cpp
blob83dd24ddf20fe74052c3d0c687610a00d7d8b1b5
2 //=============================================================================
3 /**
4 * @file Future_Set_Test.cpp
6 * This example tests the ACE Future Set and illustrates an
7 * implementation of the Active Object pattern, which is available
8 * at <http://www.dre.vanderbilt.edu/~schmidt/PDF/Act-Obj.pdf>. The
9 * Active Object itself is very simple -- it determines if numbers
10 * are prime.
12 * @author Andres Kruse <Andres.Kruse@cern.ch>
13 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
14 * @author Per Andersson <pera@ipso.se> and Johnny Tucker <jtucker@infoglide.com>
16 //=============================================================================
18 #include "test_config.h"
19 #include "ace/OS_NS_string.h"
20 #include "ace/ACE.h"
21 #include "ace/Task.h"
22 #include "ace/Message_Queue.h"
23 #include "ace/Future.h"
24 #include "ace/Future_Set.h"
25 #include "ace/Method_Request.h"
26 #include "ace/Activation_Queue.h"
27 #include <memory>
28 #include "ace/Atomic_Op.h"
29 #include "ace/Null_Mutex.h"
31 #if defined (ACE_HAS_THREADS)
33 using ATOMIC_INT = ACE_Atomic_Op<ACE_Thread_Mutex, int>;
35 // A counter for the tasks..
36 static ATOMIC_INT task_count (0);
38 /**
39 * @class Prime_Scheduler
41 * @brief Prime number scheduler for the Active Object.
43 * This class also plays the role of the Proxy and the Servant
44 * in the Active Object pattern. Naturally, these roles could
45 * be split apart from the Prime_Scheduler.
47 class Prime_Scheduler : public ACE_Task_Base
49 friend class Method_Request_work;
50 friend class Method_Request_name;
51 friend class Method_Request_end;
52 public:
53 /// Constructor.
54 Prime_Scheduler (const ACE_TCHAR *,
55 Prime_Scheduler * = 0);
57 //FUZZ: disable check_for_lack_ACE_OS
58 /// Initializer.
59 int open (void *args = 0) override;
61 /// Terminator.
62 //FUZZ: enable check_for_lack_ACE_OS
63 virtual int shutdown ();
65 /// Destructor.
66 ~Prime_Scheduler () override;
68 // = These methods are part of the Active Object Proxy interface.
69 ACE_Future<u_long> work (u_long param, int count = 1);
70 ACE_Future<const ACE_TCHAR*> name ();
71 void end ();
73 protected:
74 /// Runs the Prime_Scheduler's event loop, which dequeues
75 /// <Method_Requests> and dispatches them.
76 int svc () override;
78 // = These are the Servant methods that do the actual work.
79 u_long work_i (u_long, int);
80 const ACE_TCHAR *name_i ();
82 private:
83 // = These are the <Prime_Scheduler> implementation details.
84 ACE_TCHAR *name_;
85 ACE_Activation_Queue activation_queue_;
86 Prime_Scheduler *scheduler_;
89 /**
90 * @class Method_Request_work
92 * @brief Reification of the <work> method.
94 class Method_Request_work : public ACE_Method_Request
96 public:
97 Method_Request_work (Prime_Scheduler *,
98 u_long,
99 int,
100 ACE_Future<u_long> &);
101 ~Method_Request_work () override;
103 /// This is the entry point into the Active Object method.
104 int call () override;
106 private:
107 Prime_Scheduler *scheduler_;
109 /// Parameter to the method that's used to determine if a number if
110 /// prime.
111 u_long param_;
113 /// Unused.
114 int count_;
116 /// Store the result of the Future.
117 ACE_Future<u_long> future_result_;
120 Method_Request_work::Method_Request_work (Prime_Scheduler *new_Prime_Scheduler,
121 u_long new_param,
122 int new_count,
123 ACE_Future<u_long> &new_result)
124 : scheduler_ (new_Prime_Scheduler),
125 param_ (new_param),
126 count_ (new_count),
127 future_result_ (new_result)
129 ACE_DEBUG ((LM_DEBUG,
130 ACE_TEXT ("(%t) Method_Request_work created\n")));
133 Method_Request_work::~Method_Request_work ()
135 ACE_DEBUG ((LM_DEBUG,
136 ACE_TEXT ("(%t) Method_Request_work will be deleted.\n")));
140 Method_Request_work::call ()
142 // Dispatch the Servant's operation and store the result into the
143 // Future.
144 return this->future_result_.set (this->scheduler_->work_i
145 (this->param_,
146 this->count_));
150 * @class Method_Request_name
152 * @brief Reification of the <name> method.
154 class Method_Request_name : public ACE_Method_Request
156 public:
157 Method_Request_name (Prime_Scheduler *,
158 ACE_Future<const ACE_TCHAR*> &);
159 ~Method_Request_name () override;
161 /// This is the entry point into the Active Object method.
162 int call () override;
164 private:
165 Prime_Scheduler *scheduler_;
166 ACE_Future<const ACE_TCHAR*> future_result_;
169 Method_Request_name::Method_Request_name (Prime_Scheduler *new_scheduler,
170 ACE_Future<const ACE_TCHAR*> &new_result)
171 : scheduler_ (new_scheduler),
172 future_result_ (new_result)
174 ACE_DEBUG ((LM_DEBUG,
175 ACE_TEXT ("(%t) Method_Request_name created\n")));
178 Method_Request_name::~Method_Request_name ()
180 ACE_DEBUG ((LM_DEBUG,
181 ACE_TEXT ("(%t) Method_Request_name will be deleted.\n")));
185 Method_Request_name::call ()
187 // Dispatch the Servant's operation and store the result into the
188 // Future.
189 return future_result_.set (scheduler_->name_i ());
193 * @class Method_Request_end
195 * @brief Reification of the <end> method.
197 class Method_Request_end : public ACE_Method_Request
199 public:
200 Method_Request_end (Prime_Scheduler *new_Prime_Scheduler);
201 ~Method_Request_end () override;
202 int call () override;
204 private:
205 Prime_Scheduler *scheduler_;
208 Method_Request_end::Method_Request_end (Prime_Scheduler *scheduler)
209 : scheduler_ (scheduler)
213 Method_Request_end::~Method_Request_end ()
218 Method_Request_end::call ()
220 // Shut down the scheduler.
221 this->scheduler_->shutdown ();
222 return -1;
225 // Constructor
226 Prime_Scheduler::Prime_Scheduler (const ACE_TCHAR *newname,
227 Prime_Scheduler *new_scheduler)
228 : scheduler_ (new_scheduler)
230 ACE_NEW (this->name_,
231 ACE_TCHAR[ACE_OS::strlen (newname) + 1]);
232 ACE_OS::strcpy ((ACE_TCHAR *) this->name_,
233 newname);
234 ACE_DEBUG ((LM_DEBUG,
235 ACE_TEXT ("(%t) Prime_Scheduler %s created\n"),
236 this->name_));
239 // Destructor
241 Prime_Scheduler::~Prime_Scheduler ()
243 ACE_DEBUG ((LM_DEBUG,
244 ACE_TEXT ("(%t) Prime_Scheduler %s will be destroyed\n"),
245 this->name_));
246 delete [] this->name_;
249 // open
252 Prime_Scheduler::open (void *)
254 task_count++;
255 ACE_DEBUG ((LM_DEBUG,
256 ACE_TEXT ("(%t) Prime_Scheduler %s open\n"),
257 this->name_));
258 // Become an Active Object.
259 return this->activate (THR_BOUND | THR_DETACHED);
262 // close
265 Prime_Scheduler::shutdown ()
267 ACE_DEBUG ((LM_DEBUG,
268 ACE_TEXT ("(%t) Prime_Scheduler %s shutdown\n"),
269 this->name_));
270 task_count--;
271 return 0;
274 // Service..
277 Prime_Scheduler::svc ()
279 for (;;)
281 // Dequeue the next method request (we use an unique pointer in
282 // case an exception is thrown in the <call>).
283 std::unique_ptr<ACE_Method_Request> mo (this->activation_queue_.dequeue ());
285 ACE_DEBUG ((LM_DEBUG,
286 ACE_TEXT ("(%t) calling method request\n")));
287 // Call it.
288 if (mo->call () == -1)
289 break;
290 // Destructor automatically deletes it.
293 /* NOTREACHED */
294 return 0;
297 void
298 Prime_Scheduler::end ()
300 this->activation_queue_.enqueue (new Method_Request_end (this));
303 // Here's where the Work takes place. We compute if the parameter is
304 // a prime number.
306 u_long
307 Prime_Scheduler::work_i (u_long param,
308 int count)
310 ACE_UNUSED_ARG (count);
312 return ACE::is_prime (param, 2, param / 2);
315 const ACE_TCHAR *
316 Prime_Scheduler::name_i ()
318 return this->name_;
321 ACE_Future<const ACE_TCHAR *>
322 Prime_Scheduler::name ()
324 if (this->scheduler_)
325 // Delegate to the Prime_Scheduler.
326 return this->scheduler_->name ();
327 else
329 ACE_Future<const ACE_TCHAR*> new_future;
331 // @@ What happens if new fails here?
332 this->activation_queue_.enqueue
333 (new Method_Request_name (this,
334 new_future));
335 return new_future;
339 ACE_Future<u_long>
340 Prime_Scheduler::work (u_long newparam,
341 int newcount)
343 if (this->scheduler_) {
344 return this->scheduler_->work (newparam, newcount);
346 else {
347 ACE_Future<u_long> new_future;
349 this->activation_queue_.enqueue
350 (new Method_Request_work (this,
351 newparam,
352 newcount,
353 new_future));
354 return new_future;
358 // @@ These values should be set by the command line options!
360 // Total number of loops.
361 static int n_loops = 100;
363 using u_long_key = ACE_Future_Rep<u_long> *;
364 using u_long_value = ACE_Future_Holder<u_long> *;
366 using char_star_key = ACE_Future_Rep<const ACE_TCHAR *> *;
367 using char_star_value = ACE_Future_Holder<const ACE_TCHAR *> *;
369 #endif /* ACE_HAS_THREADS */
372 run_main (int, ACE_TCHAR *[])
374 ACE_START_TEST (ACE_TEXT ("Future_Set_Test"));
376 #if defined (ACE_HAS_THREADS)
377 // @@ Should make these be <auto_ptr>s...
378 Prime_Scheduler *andres, *peter, *helmut, *matias;
380 // Create active objects..
381 ACE_NEW_RETURN (andres,
382 Prime_Scheduler (ACE_TEXT ("andres")),
383 -1);
384 int result = andres->open ();
385 ACE_TEST_ASSERT (result != -1);
386 ACE_NEW_RETURN (peter,
387 Prime_Scheduler (ACE_TEXT ("peter")),
388 -1);
389 result = peter->open ();
390 ACE_TEST_ASSERT (result != -1);
391 ACE_NEW_RETURN (helmut,
392 Prime_Scheduler (ACE_TEXT ("helmut")),
393 -1);
394 result = helmut->open ();
395 ACE_TEST_ASSERT (result != -1);
397 // Matias passes all asynchronous method calls on to Andres...
398 ACE_NEW_RETURN (matias,
399 Prime_Scheduler (ACE_TEXT ("matias"),
400 andres),
401 -1);
402 result = matias->open ();
403 ACE_TEST_ASSERT (result != -1);
405 ACE_Future<u_long> fresulta;
406 ACE_Future<u_long> fresultb;
407 ACE_Future<u_long> fresultc;
408 ACE_Future<u_long> fresultd;
409 ACE_Future<const ACE_TCHAR *> fname;
411 ACE_Future_Set<u_long> fseta;
412 ACE_Future_Set<u_long> fsetb;
413 ACE_Future_Set<u_long> fsetc;
414 ACE_Future_Set<u_long> fsetd;
415 ACE_Future_Set<const ACE_TCHAR *> fsetname;
417 ACE_DEBUG ((LM_DEBUG,
418 ACE_TEXT ("(%t) initializing future sets with non-blocking call\n")));
420 for (int i = 0; i < n_loops; i++)
422 // Spawn off the methods, which run in a separate thread as
423 // active object invocations.
424 fresulta = andres->work (9013);
425 fresultb = peter->work (9013);
426 fresultc = helmut->work (9013);
427 fresultd = matias->work (9013);
428 fname = andres->name ();
430 fsetname.insert (fname);
431 fname = peter->name ();
432 fsetname.insert (fname);
433 fname = helmut->name ();
435 fseta.insert (fresulta);
436 fsetb.insert (fresultb);
437 fsetc.insert (fresultc);
438 fsetd.insert (fresultd);
439 fsetname.insert (fname);
443 // See if the result is available...
445 if (!fseta.is_empty ())
446 ACE_DEBUG ((LM_DEBUG,
447 ACE_TEXT ("(%t) wow.. set a is not empty.....\n")));
449 if (!fsetb.is_empty ())
450 ACE_DEBUG ((LM_DEBUG,
451 ACE_TEXT ("(%t) wow.. set b is not empty.....\n")));
453 if (!fsetc.is_empty ())
454 ACE_DEBUG ((LM_DEBUG,
455 ACE_TEXT ("(%t) wow.. set c is not empty.....\n")));
457 if (!fsetd.is_empty ())
458 ACE_DEBUG ((LM_DEBUG,
459 ACE_TEXT ("(%t) wow.. set d is not empty.....\n")));
461 if (!fsetname.is_empty ())
462 ACE_DEBUG ((LM_DEBUG,
463 ACE_TEXT ("(%t) wow.. set name is not empty.....\n")));
465 ACE_DEBUG ((LM_DEBUG,
466 ACE_TEXT ("(%t) non-blocking calls done... now blocking...\n")));
468 // Save the result of fresulta.
470 u_long resulta = 0;
471 u_long resultb = 0;
472 u_long resultc = 0;
473 u_long resultd = 0;
475 u_int count = 0;
476 while (fseta.next_readable (fresulta))
478 fresulta.get (resulta);
480 ACE_DEBUG ((LM_DEBUG,
481 ACE_TEXT ("(%t) result(%u) a %u\n"),
482 count,
483 (u_int) resulta));
486 count = 0;
487 while (fsetb.next_readable (fresultb))
489 fresultb.get (resultb);
491 ACE_DEBUG ((LM_DEBUG,
492 ACE_TEXT ("(%t) result(%u) b %u\n"),
493 count,
494 (u_int) resultb));
497 count = 0;
498 while (fsetc.next_readable (fresultc))
500 fresultc.get (resultc);
502 ACE_DEBUG ((LM_DEBUG,
503 ACE_TEXT ("(%t) result(%u) c %u\n"),
504 count,
505 (u_int) resultc));
508 count = 0;
509 while (fsetd.next_readable (fresultd))
511 fresultd.get (resultd);
513 ACE_DEBUG ((LM_DEBUG,
514 ACE_TEXT ("(%t) result(%u) d %u\n"),
515 count,
516 (u_int) resultd));
519 const ACE_TCHAR *name = 0;
520 count = 0;
521 while (fsetname.next_readable (fname))
523 fname.get (name);
525 ACE_DEBUG ((LM_DEBUG,
526 ACE_TEXT ("(%t) result(%u) name %s\n"),
527 count,
528 name));
531 if (fseta.is_empty ())
532 ACE_DEBUG ((LM_DEBUG,
533 ACE_TEXT ("(%t) wow.. set a is empty.....\n")));
535 if (fsetb.is_empty ())
536 ACE_DEBUG ((LM_DEBUG,
537 ACE_TEXT ("(%t) wow.. set b is empty.....\n")));
539 if (fsetc.is_empty ())
540 ACE_DEBUG ((LM_DEBUG,
541 ACE_TEXT ("(%t) wow.. set c is empty.....\n")));
543 if (fsetd.is_empty ())
544 ACE_DEBUG ((LM_DEBUG,
545 ACE_TEXT ("(%t) wow.. set d is empty.....\n")));
547 if (fsetname.is_empty ())
548 ACE_DEBUG ((LM_DEBUG,
549 ACE_TEXT ("(%t) wow.. set name is empty.....\n")));
551 ACE_DEBUG ((LM_DEBUG,
552 ACE_TEXT ("(%t) task_count %d\n"),
553 task_count.value () ));
555 // Close things down.
556 andres->end ();
557 peter->end ();
558 helmut->end ();
559 matias->end ();
561 ACE_Thread_Manager::instance ()->wait ();
562 ACE_DEBUG ((LM_DEBUG,
563 ACE_TEXT ("(%t) task_count %d\n"),
564 task_count.value () ));
566 delete andres;
567 delete peter;
568 delete helmut;
569 delete matias;
571 #else
572 ACE_ERROR ((LM_INFO,
573 ACE_TEXT ("threads not supported on this platform\n")));
574 #endif /* ACE_HAS_THREADS */
575 ACE_END_TEST;
576 return 0;