summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog20
-rw-r--r--ChangeLogs/ChangeLog-02a20
-rw-r--r--ChangeLogs/ChangeLog-03a20
-rw-r--r--ace/Select_Reactor_T.cpp27
-rw-r--r--ace/Select_Reactor_T.h12
-rw-r--r--ace/Synch.h13
-rw-r--r--ace/Synch.i11
-rw-r--r--ace/TP_Reactor.cpp10
-rw-r--r--ace/TP_Reactor.h6
-rw-r--r--ace/Token.cpp10
-rw-r--r--ace/Token.h35
-rw-r--r--ace/Token.i12
-rw-r--r--tests/Makefile1
-rw-r--r--tests/Token_Strategy_Test.cpp259
-rw-r--r--tests/run_test.lst1
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