diff options
Diffstat (limited to 'ACE/tests/Thread_Mutex_Test.cpp')
-rw-r--r-- | ACE/tests/Thread_Mutex_Test.cpp | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/ACE/tests/Thread_Mutex_Test.cpp b/ACE/tests/Thread_Mutex_Test.cpp new file mode 100644 index 00000000000..a463e72b523 --- /dev/null +++ b/ACE/tests/Thread_Mutex_Test.cpp @@ -0,0 +1,276 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// tests +// +// = FILENAME +// Thread_Mutex_Test.cpp +// +// = DESCRIPTION +// This test illustrates the functionality of the +// ACE_Thread_Mutex. The test acquires and releases mutexes. No +// command line arguments are needed to run the test. +// +// = AUTHOR +// Prashant Jain <pjain@cs.wustl.edu> and Douglas C. Schmidt <schmidt@cs.wustl.edu> +// +// ============================================================================ + +#include "test_config.h" +#include "ace/Thread_Manager.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID(tests, Thread_Mutex_Test, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "ace/Guard_T.h" + +// For all platforms except for Windows use the ACE_Thread_Mutex. +// Since Windows only supports timed process mutexes and not +// timed thread mutexes, use ACE_Process_Mutex. +#if defined (ACE_HAS_WTHREADS) +# include "ace/Process_Mutex.h" + typedef ACE_Process_Mutex ACE_TEST_MUTEX; +#else +# include "ace/Thread_Mutex.h" + typedef ACE_Thread_Mutex ACE_TEST_MUTEX; +#endif + +#if !defined (ACE_HAS_MUTEX_TIMEOUTS) +static int reported_notsup = 0; +#endif /* ACE_HAS_MUTEX_TIMEOUTS */ + +static void * +test (void *args) +{ + ACE_TEST_MUTEX *mutex = (ACE_TEST_MUTEX *) args; + ACE_UNUSED_ARG (mutex); // Suppress ghs warning about unused local "mutex". + ACE_OS::srand (ACE_OS::time (0)); + + for (size_t i = 0; i < ACE_MAX_ITERATIONS / 2; i++) + { + int result = 0; + + // First attempt to acquire the mutex with a timeout to verify + // that mutex timeouts are working. + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) = trying timed acquire on ") + ACE_TEXT ("iteration %d\n"), + i)); + + ACE_Time_Value delta (1, 0); // One second timeout + ACE_Time_Value timeout = ACE_OS::gettimeofday (); + timeout += delta; // Must pass absolute time to acquire(). + + if (mutex->acquire (timeout) != 0) + { + if (errno == ETIME) + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) = mutex acquisition ") + ACE_TEXT ("timed out\n"))); + else if (errno == ENOTSUP) + { +#if !defined (ACE_HAS_MUTEX_TIMEOUTS) + if (!reported_notsup) + { + ACE_DEBUG ((LM_INFO, + ACE_TEXT ("(%P|%t) %p, but ACE_HAS_MUTEX_TIMEOUTS is not defined - Ok\n"), + ACE_TEXT ("mutex timed acquire"))); + reported_notsup = 1; + } +#else + ACE_DEBUG ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p - maybe ACE_HAS_MUTEX_TIMEOUTS should not be defined?\n"), + ACE_TEXT ("mutex timed acquire"))); +#endif /* ACE_HAS_MUTEX_TIMEOUTS */ + } + else + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n%a"), + ACE_TEXT ("mutex timeout failed\n"))); + return 0; + } + } + else + { + result = mutex->release (); + ACE_ASSERT (result == 0); + } + + // Now try the standard mutex. + + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) = trying to acquire on iteration %d\n"), + i)); + result = mutex->acquire (); + ACE_ASSERT (result == 0); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) = acquired on iteration %d\n"), + i)); + + // Sleep for a random amount of time between 0 and 2 seconds. + // Note that it's ok to use rand() here because we are running + // within the critical section defined by the Thread_Mutex. + ACE_OS::sleep (ACE_OS::rand () % 2); + + result = mutex->release (); + ACE_ASSERT (result == 0); + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) = released on iteration %d\n"), + i)); + + // Basic ACE_Guard usage - automatically acquire the mutex on + // guard construction and automatically release it on + // destruction. + { + // Construct an ACE_Guard to implicitly acquire the mutex. + ACE_Guard<ACE_TEST_MUTEX> guard (*mutex); + ACE_ASSERT (guard.locked () != 0); + + // Perform some operation which might exit the current scope + // prematurely, e.g. by returning or throwing an exception. + // ... + + // ACE_Guard object is destroyed when exiting scope and guard + // destructor automatically releases mutex. + } + + // Use an ACE_Guard to automatically acquire a mutex, but release + // the mutex early. + { + // Construct an ACE_Guard to implicitly acquire the mutex. + ACE_Guard<ACE_TEST_MUTEX> guard (*mutex); + ACE_ASSERT (guard.locked () != 0); + + // Perform some operation which might exit the current scope + // prematurely, e.g. by returning or throwing an exception. + // ... + + // Release the mutex since we no longer need it. + guard.release (); + ACE_ASSERT (guard.locked () == 0); + + // Do something else which does not require the mutex to be locked. + // ... + + // ACE_Guard object's destructor will not release the mutex. + } + + // Use an ACE_Guard to automatically acquire a mutex, but + // relinquish ownership of the lock so that the mutex is not + // automatically released on guard destruction. This is useful + // when an operation might not release the mutex in some + // conditions, in which case responsibility for releasing it is + // passed to someone else. + { + // Construct an ACE_Guard to implicitly acquire the mutex. + ACE_Guard<ACE_TEST_MUTEX> guard (*mutex); + ACE_ASSERT (guard.locked () != 0); + + // Perform some operation which might exit the current scope + // prematurely, e.g. by returning or throwing an exception. + // ... + + // Relinquish ownership of the mutex lock. Someone else must + // now release it. + guard.disown (); + ACE_ASSERT (guard.locked () == 0); + + // ACE_Guard object's destructor will not release the mutex. + } + // We are now responsible for releasing the mutex. + result = mutex->release (); + ACE_ASSERT (result == 0); + + // Construct an ACE_Guard without automatically acquiring the lock. + { + // Construct an ACE_Guard object without automatically + // acquiring the mutex or taking ownership of an existing + // lock. The third parameter tells the guard that the mutex + // has not been locked. + ACE_Guard<ACE_TEST_MUTEX> guard (*mutex, 0, 0); + ACE_ASSERT (guard.locked () == 0); + + // Conditionally acquire the mutex. + if (i % 2 == 0) + { + guard.acquire (); + ACE_ASSERT (guard.locked () != 0); + } + + // Perform some operation that might exit the current scope + // prematurely, e.g. by returning or throwing an exception. + // ... + + // ACE_Guard object is destroyed when exiting scope and guard + // destructor automatically releases if it was acquired above. + } + + // Use an ACE_Guard to take ownership of a previously acquired + // mutex. + timeout = ACE_OS::gettimeofday (); + timeout += delta; // Must pass absolute time to acquire(). + if (mutex->acquire (timeout) == 0) + { + // Construct an ACE_Guard object without automatically + // acquiring the mutex, but instead take ownership of the + // existing lock. The third parameter tells the guard that + // the mutex has already been locked. + ACE_Guard<ACE_TEST_MUTEX> guard (*mutex, 0, 1); + ACE_ASSERT (guard.locked () != 0); + + // Perform some operation which might exit the current scope + // prematurely, e.g. by returning or throwing an exception. + // ... + + // ACE_Guard object is destroyed when exiting scope and guard + // destructor automatically releases mutex. + } + } + + return 0; +} +#endif /* ACE_HAS_THREADS */ + +static void +spawn (void) +{ +#if defined (ACE_HAS_THREADS) + ACE_TEST_MUTEX mutex; + + const u_int n_threads = ACE_MAX_THREADS; + + if (ACE_Thread_Manager::instance ()->spawn_n (n_threads, + ACE_THR_FUNC (test), + (void *) &mutex, + THR_NEW_LWP | THR_DETACHED) == -1) + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n%a"), + ACE_TEXT ("thread create failed"))); + + // Wait for the threads to exit. + ACE_Thread_Manager::instance ()->wait (); + +#else + ACE_ERROR ((LM_INFO, + ACE_TEXT ("threads not supported on this platform\n"))); +#endif /* ACE_HAS_THREADS */ +} + +int +run_main (int, ACE_TCHAR *[]) +{ + ACE_START_TEST (ACE_TEXT ("Thread_Mutex_Test")); + + spawn (); + + ACE_END_TEST; + return 0; +} |