2 //=============================================================================
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
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"
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"
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);
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
;
54 Prime_Scheduler (const ACE_TCHAR
*,
55 Prime_Scheduler
* = 0);
57 //FUZZ: disable check_for_lack_ACE_OS
59 int open (void *args
= 0) override
;
62 //FUZZ: enable check_for_lack_ACE_OS
63 virtual int shutdown ();
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 ();
74 /// Runs the Prime_Scheduler's event loop, which dequeues
75 /// <Method_Requests> and dispatches them.
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 ();
83 // = These are the <Prime_Scheduler> implementation details.
85 ACE_Activation_Queue activation_queue_
;
86 Prime_Scheduler
*scheduler_
;
90 * @class Method_Request_work
92 * @brief Reification of the <work> method.
94 class Method_Request_work
: public ACE_Method_Request
97 Method_Request_work (Prime_Scheduler
*,
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
;
107 Prime_Scheduler
*scheduler_
;
109 /// Parameter to the method that's used to determine if a number if
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
,
123 ACE_Future
<u_long
> &new_result
)
124 : scheduler_ (new_Prime_Scheduler
),
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
144 return this->future_result_
.set (this->scheduler_
->work_i
150 * @class Method_Request_name
152 * @brief Reification of the <name> method.
154 class Method_Request_name
: public ACE_Method_Request
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
;
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
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
200 Method_Request_end (Prime_Scheduler
*new_Prime_Scheduler
);
201 ~Method_Request_end () override
;
202 int call () override
;
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 ();
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_
,
234 ACE_DEBUG ((LM_DEBUG
,
235 ACE_TEXT ("(%t) Prime_Scheduler %s created\n"),
241 Prime_Scheduler::~Prime_Scheduler ()
243 ACE_DEBUG ((LM_DEBUG
,
244 ACE_TEXT ("(%t) Prime_Scheduler %s will be destroyed\n"),
246 delete [] this->name_
;
252 Prime_Scheduler::open (void *)
255 ACE_DEBUG ((LM_DEBUG
,
256 ACE_TEXT ("(%t) Prime_Scheduler %s open\n"),
258 // Become an Active Object.
259 return this->activate (THR_BOUND
| THR_DETACHED
);
265 Prime_Scheduler::shutdown ()
267 ACE_DEBUG ((LM_DEBUG
,
268 ACE_TEXT ("(%t) Prime_Scheduler %s shutdown\n"),
277 Prime_Scheduler::svc ()
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")));
288 if (mo
->call () == -1)
290 // Destructor automatically deletes it.
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
307 Prime_Scheduler::work_i (u_long param
,
310 ACE_UNUSED_ARG (count
);
312 return ACE::is_prime (param
, 2, param
/ 2);
316 Prime_Scheduler::name_i ()
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 ();
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,
340 Prime_Scheduler::work (u_long newparam
,
343 if (this->scheduler_
) {
344 return this->scheduler_
->work (newparam
, newcount
);
347 ACE_Future
<u_long
> new_future
;
349 this->activation_queue_
.enqueue
350 (new Method_Request_work (this,
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")),
384 int result
= andres
->open ();
385 ACE_TEST_ASSERT (result
!= -1);
386 ACE_NEW_RETURN (peter
,
387 Prime_Scheduler (ACE_TEXT ("peter")),
389 result
= peter
->open ();
390 ACE_TEST_ASSERT (result
!= -1);
391 ACE_NEW_RETURN (helmut
,
392 Prime_Scheduler (ACE_TEXT ("helmut")),
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"),
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.
476 while (fseta
.next_readable (fresulta
))
478 fresulta
.get (resulta
);
480 ACE_DEBUG ((LM_DEBUG
,
481 ACE_TEXT ("(%t) result(%u) a %u\n"),
487 while (fsetb
.next_readable (fresultb
))
489 fresultb
.get (resultb
);
491 ACE_DEBUG ((LM_DEBUG
,
492 ACE_TEXT ("(%t) result(%u) b %u\n"),
498 while (fsetc
.next_readable (fresultc
))
500 fresultc
.get (resultc
);
502 ACE_DEBUG ((LM_DEBUG
,
503 ACE_TEXT ("(%t) result(%u) c %u\n"),
509 while (fsetd
.next_readable (fresultd
))
511 fresultd
.get (resultd
);
513 ACE_DEBUG ((LM_DEBUG
,
514 ACE_TEXT ("(%t) result(%u) d %u\n"),
519 const ACE_TCHAR
*name
= 0;
521 while (fsetname
.next_readable (fname
))
525 ACE_DEBUG ((LM_DEBUG
,
526 ACE_TEXT ("(%t) result(%u) name %s\n"),
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.
561 ACE_Thread_Manager::instance ()->wait ();
562 ACE_DEBUG ((LM_DEBUG
,
563 ACE_TEXT ("(%t) task_count %d\n"),
564 task_count
.value () ));
573 ACE_TEXT ("threads not supported on this platform\n")));
574 #endif /* ACE_HAS_THREADS */