diff options
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | ChangeLogs/ChangeLog-02a | 20 | ||||
-rw-r--r-- | ChangeLogs/ChangeLog-03a | 20 | ||||
-rw-r--r-- | ace/Select_Reactor_T.cpp | 27 | ||||
-rw-r--r-- | ace/Select_Reactor_T.h | 12 | ||||
-rw-r--r-- | ace/Synch.h | 13 | ||||
-rw-r--r-- | ace/Synch.i | 11 | ||||
-rw-r--r-- | ace/TP_Reactor.cpp | 10 | ||||
-rw-r--r-- | ace/TP_Reactor.h | 6 | ||||
-rw-r--r-- | ace/Token.cpp | 10 | ||||
-rw-r--r-- | ace/Token.h | 35 | ||||
-rw-r--r-- | ace/Token.i | 12 | ||||
-rw-r--r-- | tests/Makefile | 1 | ||||
-rw-r--r-- | tests/Token_Strategy_Test.cpp | 259 | ||||
-rw-r--r-- | tests/run_test.lst | 1 |
15 files changed, 433 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog index 9a1587b1dff..6bef74555f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Mon Feb 25 13:50:43 2002 UTC Don Hinton <dhinton@ieee.org> + + * ace/Token.{h|i|cpp}: Added the ability to chose the queueing strategy, + FIFO or LIFO, by using the queueing_strategy() methods. The default + is FIFO, which was the previous behavior. Now ACE_Token_Queue::insert_entry() + is always called with the queueing_strategy in order to determine where + the thread should requeue itself. + + * ace/Synch.{h|i}: Added queueing strategy methods to ACE_Noop_Token. + + * ace/Select_Reactor_T.{h|cpp}: + * ace/TP_Reactor.{h|cpp}: Added QUEUEING_STRATEGY parameter to + ACE_Select_Reactor_Token_T, ACE_Select_Reactor_T, and ACE_TP_Reactor + ctors with FIFO default. + + * tests/Token_Strategy_Test.cpp : + * tests/Makefile : + * tests/run_test.lst: Added new Token_Strategy_Test.cpp to test the + FIFO/LIFO strategies. + Mon Feb 25 13:44:12 2002 Johnny Willemsen <jwillemsen@remedy.nl> * docs/tutorials/018/Test_T.h: diff --git a/ChangeLogs/ChangeLog-02a b/ChangeLogs/ChangeLog-02a index 9a1587b1dff..6bef74555f9 100644 --- a/ChangeLogs/ChangeLog-02a +++ b/ChangeLogs/ChangeLog-02a @@ -1,3 +1,23 @@ +Mon Feb 25 13:50:43 2002 UTC Don Hinton <dhinton@ieee.org> + + * ace/Token.{h|i|cpp}: Added the ability to chose the queueing strategy, + FIFO or LIFO, by using the queueing_strategy() methods. The default + is FIFO, which was the previous behavior. Now ACE_Token_Queue::insert_entry() + is always called with the queueing_strategy in order to determine where + the thread should requeue itself. + + * ace/Synch.{h|i}: Added queueing strategy methods to ACE_Noop_Token. + + * ace/Select_Reactor_T.{h|cpp}: + * ace/TP_Reactor.{h|cpp}: Added QUEUEING_STRATEGY parameter to + ACE_Select_Reactor_Token_T, ACE_Select_Reactor_T, and ACE_TP_Reactor + ctors with FIFO default. + + * tests/Token_Strategy_Test.cpp : + * tests/Makefile : + * tests/run_test.lst: Added new Token_Strategy_Test.cpp to test the + FIFO/LIFO strategies. + Mon Feb 25 13:44:12 2002 Johnny Willemsen <jwillemsen@remedy.nl> * docs/tutorials/018/Test_T.h: diff --git a/ChangeLogs/ChangeLog-03a b/ChangeLogs/ChangeLog-03a index 9a1587b1dff..6bef74555f9 100644 --- a/ChangeLogs/ChangeLog-03a +++ b/ChangeLogs/ChangeLog-03a @@ -1,3 +1,23 @@ +Mon Feb 25 13:50:43 2002 UTC Don Hinton <dhinton@ieee.org> + + * ace/Token.{h|i|cpp}: Added the ability to chose the queueing strategy, + FIFO or LIFO, by using the queueing_strategy() methods. The default + is FIFO, which was the previous behavior. Now ACE_Token_Queue::insert_entry() + is always called with the queueing_strategy in order to determine where + the thread should requeue itself. + + * ace/Synch.{h|i}: Added queueing strategy methods to ACE_Noop_Token. + + * ace/Select_Reactor_T.{h|cpp}: + * ace/TP_Reactor.{h|cpp}: Added QUEUEING_STRATEGY parameter to + ACE_Select_Reactor_Token_T, ACE_Select_Reactor_T, and ACE_TP_Reactor + ctors with FIFO default. + + * tests/Token_Strategy_Test.cpp : + * tests/Makefile : + * tests/run_test.lst: Added new Token_Strategy_Test.cpp to test the + FIFO/LIFO strategies. + Mon Feb 25 13:44:12 2002 Johnny Willemsen <jwillemsen@remedy.nl> * docs/tutorials/018/Test_T.h: diff --git a/ace/Select_Reactor_T.cpp b/ace/Select_Reactor_T.cpp index 4f9575dc083..3790c37e474 100644 --- a/ace/Select_Reactor_T.cpp +++ b/ace/Select_Reactor_T.cpp @@ -196,17 +196,30 @@ ACE_Select_Reactor_Token_T<ACE_SELECT_REACTOR_MUTEX>::dump (void) const template <class ACE_SELECT_REACTOR_MUTEX> ACE_Select_Reactor_Token_T<ACE_SELECT_REACTOR_MUTEX>::ACE_Select_Reactor_Token_T - (ACE_Select_Reactor_Impl &r) + (ACE_Select_Reactor_Impl &r, + int s_queue) : select_reactor_ (&r) { ACE_TRACE ("ACE_Select_Reactor_Token_T::ACE_Select_Reactor_Token"); + +#if defined (ACE_SELECT_REACTOR_HAS_DEADLOCK_DETECTION) + ACE_UNUSED_ARG (s_queue); +#else + this->queueing_strategy (s_queue); +#endif } template <class ACE_SELECT_REACTOR_MUTEX> -ACE_Select_Reactor_Token_T<ACE_SELECT_REACTOR_MUTEX>::ACE_Select_Reactor_Token_T (void) +ACE_Select_Reactor_Token_T<ACE_SELECT_REACTOR_MUTEX>::ACE_Select_Reactor_Token_T (int s_queue) : select_reactor_ (0) { ACE_TRACE ("ACE_Select_Reactor_Token_T::ACE_Select_Reactor_Token"); + +#if defined (ACE_SELECT_REACTOR_HAS_DEADLOCK_DETECTION) + ACE_UNUSED_ARG (s_queue); +#else + this->queueing_strategy (s_queue); +#endif } template <class ACE_SELECT_REACTOR_MUTEX> @@ -515,8 +528,9 @@ ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::ACE_Select_Reactor_T ACE_Timer_Queue *tq, int disable_notify_pipe, ACE_Reactor_Notify *notify, - int mask_signals) - : token_ (*this), + int mask_signals, + int s_queue) + : token_ (*this, s_queue), lock_adapter_ (token_), deactivated_ (0), mask_signals_ (mask_signals) @@ -566,8 +580,9 @@ ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::ACE_Select_Reactor_T ACE_Timer_Queue *tq, int disable_notify_pipe, ACE_Reactor_Notify *notify, - int mask_signals) - : token_ (*this), + int mask_signals, + int s_queue) + : token_ (*this, s_queue), lock_adapter_ (token_), deactivated_ (0), mask_signals_ (mask_signals) diff --git a/ace/Select_Reactor_T.h b/ace/Select_Reactor_T.h index 66db768828e..27c1d2f2910 100644 --- a/ace/Select_Reactor_T.h +++ b/ace/Select_Reactor_T.h @@ -70,8 +70,10 @@ template <class ACE_SELECT_REACTOR_MUTEX> class ACE_Select_Reactor_Token_T : public ACE_SELECT_REACTOR_MUTEX { public: - ACE_Select_Reactor_Token_T (ACE_Select_Reactor_Impl &r); - ACE_Select_Reactor_Token_T (void); + + ACE_Select_Reactor_Token_T (ACE_Select_Reactor_Impl &r, + int s_queue = ACE_SELECT_REACTOR_MUTEX::FIFO); + ACE_Select_Reactor_Token_T (int s_queue = ACE_SELECT_REACTOR_MUTEX::FIFO); virtual ~ACE_Select_Reactor_Token_T (void); /// Called just before the ACE_Event_Handler goes to sleep. @@ -122,7 +124,8 @@ public: ACE_Timer_Queue * = 0, int disable_notify_pipe = 0, ACE_Reactor_Notify *notify = 0, - int mask_signals = 1); + int mask_signals = 1, + int s_queue = ACE_SELECT_REACTOR_TOKEN::FIFO); /// Initialize @c ACE_Select_Reactor with size @arg size. /// If @arg disable_notify_pipe is non-0 then the reactor will @@ -146,7 +149,8 @@ public: ACE_Timer_Queue * = 0, int disable_notify_pipe = 0, ACE_Reactor_Notify *notify = 0, - int mask_signals = 1); + int mask_signals = 1, + int s_queue = ACE_SELECT_REACTOR_TOKEN::FIFO); /** * Initialize the @c ACE_Select_Reactor to manage diff --git a/ace/Synch.h b/ace/Synch.h index f46053bef2b..c3099776f4d 100644 --- a/ace/Synch.h +++ b/ace/Synch.h @@ -687,6 +687,19 @@ public: class ACE_Export ACE_Noop_Token : public ACE_Null_Mutex { public: + /// Queueing strategy + enum QUEUEING_STRATEGY + { + FIFO = -1, + LIFO = 0 + }; + + /// Get queueing strategy. + int queueing_strategy (void); + + /// Set queueing strategy. + void queueing_strategy (int queueing_strategy); + int renew (int = 0, ACE_Time_Value * =0); /// Dump the state of an object. diff --git a/ace/Synch.i b/ace/Synch.i index 4bb95145df5..6c0e1de93c0 100644 --- a/ace/Synch.i +++ b/ace/Synch.i @@ -817,6 +817,17 @@ ACE_Null_Mutex::dump (void) const } ACE_INLINE int +ACE_Noop_Token::queueing_strategy (void) +{ + return -1; +} + +ACE_INLINE void +ACE_Noop_Token::queueing_strategy (int queueing_strategy) +{ +} + +ACE_INLINE int ACE_Noop_Token::renew (int, ACE_Time_Value *) { return 0; diff --git a/ace/TP_Reactor.cpp b/ace/TP_Reactor.cpp index e6b0d189f89..2669e47d287 100644 --- a/ace/TP_Reactor.cpp +++ b/ace/TP_Reactor.cpp @@ -99,8 +99,9 @@ ACE_TP_Token_Guard::acquire_token (ACE_Time_Value *max_wait_time) ACE_TP_Reactor::ACE_TP_Reactor (ACE_Sig_Handler *sh, ACE_Timer_Queue *tq, - int mask_signals) - : ACE_Select_Reactor (sh, tq, 0, 0, mask_signals) + int mask_signals, + int s_queue) + : ACE_Select_Reactor (sh, tq, 0, 0, mask_signals, s_queue) { ACE_TRACE ("ACE_TP_Reactor::ACE_TP_Reactor"); this->supress_notify_renew (1); @@ -110,8 +111,9 @@ ACE_TP_Reactor::ACE_TP_Reactor (size_t size, int rs, ACE_Sig_Handler *sh, ACE_Timer_Queue *tq, - int mask_signals) - : ACE_Select_Reactor (size, rs, sh, tq, 0, 0, mask_signals) + int mask_signals, + int s_queue) + : ACE_Select_Reactor (size, rs, sh, tq, 0, 0, mask_signals, s_queue) { ACE_TRACE ("ACE_TP_Reactor::ACE_TP_Reactor"); this->supress_notify_renew (1); diff --git a/ace/TP_Reactor.h b/ace/TP_Reactor.h index e51abd99db9..8c51ceff58b 100644 --- a/ace/TP_Reactor.h +++ b/ace/TP_Reactor.h @@ -170,7 +170,8 @@ public: /// Initialize <ACE_TP_Reactor> with the default size. ACE_TP_Reactor (ACE_Sig_Handler * = 0, ACE_Timer_Queue * = 0, - int mask_signals = 1); + int mask_signals = 1, + int s_queue = ACE_Select_Reactor_Token::FIFO); /** * Initialize the <ACE_TP_Reactor> to manage @@ -184,7 +185,8 @@ public: int restart = 0, ACE_Sig_Handler * = 0, ACE_Timer_Queue * = 0, - int mask_signals = 1); + int mask_signals = 1, + int s_queue = ACE_Select_Reactor_Token::FIFO); // = Event loop drivers. diff --git a/ace/Token.cpp b/ace/Token.cpp index cb2b2d2c618..f15de7d1fe4 100644 --- a/ace/Token.cpp +++ b/ace/Token.cpp @@ -165,7 +165,8 @@ ACE_Token::ACE_Token (const ACE_TCHAR *name, void *any) in_use_ (0), waiters_ (0), nesting_level_ (0), - attributes_ (USYNC_THREAD) + attributes_ (USYNC_THREAD), + queueing_strategy_ (FIFO) { // ACE_TRACE ("ACE_Token::ACE_Token"); } @@ -231,7 +232,7 @@ ACE_Token::shared_acquire (void (*sleep_hook_func)(void *), ACE_Token::ACE_Token_Queue_Entry my_entry (this->lock_, thr_id, this->attributes_); - queue->insert_entry (my_entry); + queue->insert_entry (my_entry, this->queueing_strategy_); this->waiters_++; // Execute appropriate <sleep_hook> callback. (@@ should these @@ -383,7 +384,10 @@ ACE_Token::renew (int requeue_position, this->owner_); this_threads_queue->insert_entry (my_entry, - requeue_position); + // if requeue_position == 0 then we want to go next, + // otherwise use the queueing strategy, which might also + // happen to be 0. + requeue_position == 0 ? 0 : this->queueing_strategy_); this->waiters_++; // Remember nesting level... diff --git a/ace/Token.h b/ace/Token.h index 8d9cc641059..45bb41826aa 100644 --- a/ace/Token.h +++ b/ace/Token.h @@ -34,7 +34,7 @@ * @class ACE_Token * * @brief Class that acquires, renews, and releases a synchronization - * token that is serviced in strict FIFO ordering and that also + * token that is serviced in strict FIFO/LIFO ordering and that also * supports (1) recursion and (2) readers/writer semantics. * * This class is a more general-purpose synchronization mechanism @@ -44,9 +44,9 @@ * <acquire> multiple times, however, it must call <release> an * equal number of times before the token is actually released. * Threads that are blocked awaiting the token are serviced in - * strict FIFO order as other threads release the token (Solaris + * strict FIFO/LIFO order as other threads release the token (Solaris * and Pthread mutexes don't strictly enforce an acquisition - * order). There are two FIFO lists within the class. Write + * order). There are two lists within the class. Write * acquires always have higher priority over read acquires. Which * means, if you use both write/read operations, care must be * taken to avoid starvation on the readers. Notice that the @@ -62,11 +62,31 @@ class ACE_Export ACE_Token { public: + + /** + * Available queueing strategies. + */ + enum QUEUEING_STRATEGY + { + /// FIFO, First In, First Out. + FIFO = -1, + /// LIFO, Last In, First Out + LIFO = 0 + }; + // = Initialization and termination. ACE_Token (const ACE_TCHAR *name = 0, void * = 0); virtual ~ACE_Token (void); + // = Strategies + + /// Retrieve the current queueing strategy. + int queueing_strategy (void); + + /// Set the queueing strategy. + void queueing_strategy (int queueing_strategy); + // = Synchronization operations. /** @@ -107,7 +127,7 @@ public: * you don't want to degrade the quality of service if there are * other threads waiting to get the token. If <requeue_position> == * -1 and there are other threads waiting to obtain the token we are - * queued at the end of the list of waiters. If <requeue_position> + * queued according to the queueing strategy. If <requeue_position> * > -1 then it indicates how many entries to skip over before * inserting our thread into the list of waiters (e.g., * <requeue_position> == 0 means "insert at front of the queue"). @@ -174,7 +194,7 @@ public: /// Declare the dynamic allocation hooks. ACE_ALLOC_HOOK_DECLARE; - // = The following structure implements a ACE_FIFO of waiter threads + // = The following structure implements a LIFO/FIFO queue of waiter threads // that are asleep waiting to obtain the token. struct ACE_Token_Queue_Entry @@ -270,6 +290,9 @@ private: /// The attributes for the condition variables, optimizes lock time. ACE_Condition_Attributes attributes_; + + /// Queueing strategy, LIFO/FIFO. + int queueing_strategy_; }; #if defined (__ACE_INLINE__) @@ -280,6 +303,8 @@ private: class ACE_Export ACE_Token { public: + int queueing_strategy (void) { ACE_NOTSUP_RETURN (-1); } + void queueing_strategy (int queueing_strategy) { } int acquire (ACE_Time_Value * = 0) { ACE_NOTSUP_RETURN (-1); } int tryacquire (void) { ACE_NOTSUP_RETURN (-1); } int remove (void) { ACE_NOTSUP_RETURN (-1); } diff --git a/ace/Token.i b/ace/Token.i index e5b7aaf94a9..c7c0f2d9285 100644 --- a/ace/Token.i +++ b/ace/Token.i @@ -4,6 +4,18 @@ // Token.i ACE_INLINE int +ACE_Token::queueing_strategy (void) +{ + return this->queueing_strategy_; +} + +ACE_INLINE void +ACE_Token::queueing_strategy (int queueing_strategy) +{ + this->queueing_strategy_ = queueing_strategy == -1 ? -1 : 0; +} + +ACE_INLINE int ACE_Token::remove (void) { ACE_TRACE ("ACE_Token::remove"); diff --git a/tests/Makefile b/tests/Makefile index e9228cf5695..1e98f9c69c2 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -102,6 +102,7 @@ BIN = Aio_Platform_Test \ Time_Service_Test \ Time_Value_Test \ Timer_Queue_Test \ + Token_Strategy_Test \ TP_Reactor_Test \ TSS_Test \ Vector_Test \ diff --git a/tests/Token_Strategy_Test.cpp b/tests/Token_Strategy_Test.cpp new file mode 100644 index 00000000000..33446830e3c --- /dev/null +++ b/tests/Token_Strategy_Test.cpp @@ -0,0 +1,259 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = DESCRIPTION +// This program tests the behavior of ACE_Token under a variety of senerios +// in order verify whether or not tokens are returned, and threads run, in +// a LIFO or FIFO maner. +// +// = AUTHOR +// Don Hinton <dhinton@ieee.org> +// +// ============================================================================ + + +#include "ace/Token.h" +#include "ace/Task.h" +#include "ace/Atomic_Op.h" +#include "ace/Auto_IncDec_T.h" +#include "ace/Vector_T.h" +#include "ace/Stats.h" +#include "tests/test_config.h" + + +ACE_RCSID(tests, Token_Strategy_Test, "$Id$") + +#if defined (ACE_HAS_THREADS) + +class Token_Strategy_Test : public ACE_Task<ACE_MT_SYNCH> +{ +public: + + Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy = ACE_Token::FIFO, + int threads = 5, int invocations = 10); + ~Token_Strategy_Test (void); + + int open (void *a = 0); + int svc (void); + +private: + // Number of threads for the test, must be 5 or more. + int threads_; + + // Barrier used to try to synchronize the for loop in the svc() method. + ACE_Barrier barrier_; + + // Token used to synchonize for loop. + ACE_Token token_; + + // Token strategy to use, LIFO/FIFO. + ACE_Token::QUEUEING_STRATEGY strategy_; + + // Number of loops. + int invocations_; + + // Vector of token counts, one per thread. + ACE_Vector<ACE_INT32> vec_token_count_; + + // This keeps a count of the number of threads who have the token--should always + // be 0 or 1; + ACE_Atomic_Op<ACE_Thread_Mutex, int> counter_; + + // Number of active threads in svc() method. + ACE_Atomic_Op<ACE_Thread_Mutex, int> active_; + + // Errors count, set in svc() and returned from open(). + ACE_Atomic_Op<ACE_Thread_Mutex, int> errors_; + + ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test (const Token_Strategy_Test &)); + ACE_UNIMPLEMENTED_FUNC (Token_Strategy_Test &operator= (const Token_Strategy_Test &)); +}; + + +Token_Strategy_Test::Token_Strategy_Test (ACE_Token::QUEUEING_STRATEGY strategy, int threads, int invocations) + : threads_ (threads < 5 ? 5 : threads), // need at least 5 threads to satisfy test conditions. + barrier_ (threads_), + strategy_ (strategy), + invocations_ (invocations < 10 ? 10 : invocations), // insure we loop at least a few times. + vec_token_count_ (threads_) +{ + this->counter_ = 0; + this->active_ = 0; + this->errors_ = 0; + + // Initialize the per thread counters used for generating stats. + for (int i = 0; i < this->threads_; ++i) + { + const ACE_UINT32 sample = 0; + this->vec_token_count_.push_back (sample); + } + + this->token_.queueing_strategy (this->strategy_); + + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT (" (tid = %t) Token_Test::Token_Test (\n" + " token_type = %s\n" + " thread = %d\n" + " invocations = %d\n"), + this->strategy_ == ACE_Token::FIFO ? ACE_LIB_TEXT ("FIFO") : ACE_LIB_TEXT ("LIFO"), + this->threads_, + this->invocations_)); +} + +Token_Strategy_Test::~Token_Strategy_Test (void) +{} + +int +Token_Strategy_Test::open (void *) +{ + // spawn threads in ace task... + // Make this Task into an Active Object. + this->activate (THR_BOUND | THR_DETACHED, this->threads_); + + // Wait for all the threads to exit. + this->thr_mgr ()->wait (); + return this->errors_.value (); +} + +int +Token_Strategy_Test::svc (void) +{ + int current = this->active_.value (); + ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > active_counter (this->active_); + this->barrier_.wait (); + + + //ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (tid = %t) starting loop\n"))); + for (int i = 0; i < this->invocations_; i++) + { + ACE_GUARD_RETURN (ACE_Token, lock, this->token_, -1); + this->vec_token_count_[current]++; + ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > token_count_counter (this->counter_); + + // Turn this on to watch each thread grab the token. LIFO has the interesting + // behavior that two thread seem to take turns while all the other threads wait. + if (0) + ACE_DEBUG ((LM_DEBUG, ACE_LIB_TEXT (" (tid = %t) token count = %d, " + "waiters = %d, loop: %d/%d\n"), + this->counter_.value (), + this->token_.waiters (), i + 1, + this->invocations_)); + + // Yield, then simulate some work in order to give the other threads a chance to queue up. + ACE_Thread::yield (); + for (int k = 0; k != 100; ++k) + { + ACE::is_prime (k, 2, k/2); + } + + // If we are the first thread to finish, compute the stats. + if (i + 1 == this->invocations_) + { + if (this->active_ == this->threads_) + { + ACE_Stats stats; + ACE_Stats_Value std_dev (2); + ACE_Stats_Value mean (2); + for (int i = 0; i < this->threads_; ++i) + { + stats.sample (this->vec_token_count_[i]); + } + + //stats.print_summary (2); + stats.std_dev (std_dev); + stats.mean (mean); + ACE_DEBUG ((LM_DEBUG, + ACE_LIB_TEXT (" (tid = %t) mean = %d.%d, std_dev = %d.%d, max = %d, min = %d\n"), + mean.whole (), mean.fractional (), std_dev.whole (), std_dev.fractional (), + stats.max_value (), stats.min_value ())); + + // These are pretty simplistic tests, so let me know if you have a better idea. + // The assumption is that the standard deviation will be small when using the + // FIFO strategy since all threads will share the token more or less evenly. + // In contrast, the LIFO strategy will allow the two threads to alternate, thus + // several threads will have a low, or zero, token count and create a low mean and + // high standard deviation. If the the thread count is over say 4 or 5, the + // standard deviation will actually excide the mean, hence the test. + if (this->strategy_ == ACE_Token::LIFO && + (mean.whole () > std_dev.whole () && + mean.fractional () > std_dev.fractional ())) + { + ACE_DEBUG ((LM_ERROR, + ACE_LIB_TEXT (" (tid = %t) LIFO: mean greater than std_dev.\n"))); + this->errors_++; + } + if (this->strategy_ == ACE_Token::FIFO && + (mean.whole () < std_dev.whole () && + mean.fractional () < std_dev.fractional ())) + { + ACE_DEBUG ((LM_ERROR, + ACE_LIB_TEXT (" (tid = %t) FIFO: mean less than std_dev.\n"))); + this->errors_++; + } + } + } + } + return 0; +} + + +int run_test (ACE_Token::QUEUEING_STRATEGY strategy, int threads = 5, + int invocations = 10) +{ + Token_Strategy_Test test (strategy, threads, invocations); + return test.open () == 0 ? 0 : 1; +} + +int +main (int argc, ACE_TCHAR *argv[]) +{ + ACE_START_TEST (ACE_LIB_TEXT ("Token_Strategy_Test")); + int retval = 0; + + if (argc > 3) + { + // print usage + retval = 1; + } + else + { + int threads = 5; + int invocations = 100; + + if (argc > 1) threads = atoi (argv[1]); + if (argc > 2) invocations = atoi (argv[2]); + + // New test using ACE_Token::queueing_strategy () + retval += run_test (ACE_Token::FIFO, threads, invocations); + retval += run_test (ACE_Token::LIFO, threads, invocations); + } + + ACE_END_TEST; + return retval; +} + +#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) +template class ACE_Atomic_Op<ACE_Thread_Mutex, int>; +template class ACE_Atomic_Op_Ex<ACE_Thread_Mutex, int>; +template class ACE_Vector<ACE_INT32>; +template class ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> >; +template class ACE_Guard<ACE_Token>; +#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) +#pragma instantiate ACE_Atomic_Op<ACE_Thread_Mutex, int> +#pragma instantiate ACE_Atomic_Op_Ex<ACE_Thread_Mutex, int> +#pragma instantiate ACE_Vector<ACE_INT32> +#pragma instantiate ACE_Auto_IncDec<ACE_Atomic_Op<ACE_Thread_Mutex, int> > +#pragma instantiate ACE_Guard<ACE_Token> +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ + +#else /* ACE_HAS_THREADS */ +int +main (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, ACE_LIB_TEXT ("Token_Strategy_Test: your platform doesn't support threads\n")), 1); +} +#endif /* ACE_HAS_THREADS */ diff --git a/tests/run_test.lst b/tests/run_test.lst index 93d29280520..49305fc2bd8 100644 --- a/tests/run_test.lst +++ b/tests/run_test.lst @@ -112,6 +112,7 @@ Timer_Queue_Test Timeprobe_Test Time_Service_Test: ALL !STATIC !DISABLED !missing_netsvcs TOKEN !chorus !Unicos Time_Value_Test +Token_Strategy_Test Tokens_Test: ALL MSVC !DISABLED TOKEN !chorus !Unicos TP_Reactor_Test: ALL !DISABLED TSS_Test |