diff options
Diffstat (limited to 'ACE/examples/Threads/thread_specific.cpp')
-rw-r--r-- | ACE/examples/Threads/thread_specific.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/ACE/examples/Threads/thread_specific.cpp b/ACE/examples/Threads/thread_specific.cpp new file mode 100644 index 00000000000..d69864b750c --- /dev/null +++ b/ACE/examples/Threads/thread_specific.cpp @@ -0,0 +1,226 @@ +// $Id$ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Service_Config.h" +#include "ace/Thread_Manager.h" +#include "ace/Signal.h" + +ACE_RCSID(Threads, thread_specific, "$Id$") + +#if defined (ACE_HAS_THREADS) + +#include "thread_specific.h" + +// Static variables. +ACE_MT (ACE_Thread_Mutex Errno::lock_); +int Errno::flags_; + +// This is our thread-specific error handler... +static ACE_TSS<Errno> tss_error; + +// Serializes output via cout. +static ACE_SYNCH_MUTEX printf_lock; + +#if defined (ACE_HAS_THREADS) +typedef ACE_TSS_Guard<ACE_Thread_Mutex> GUARD; +#else +typedef ACE_Guard<ACE_Null_Mutex> GUARD; +#endif /* ACE_HAS_THREADS */ + +extern "C" void +cleanup (void *ptr) +{ + ACE_DEBUG ((LM_DEBUG, + "(%t) in cleanup, ptr = %x\n", + ptr)); + + delete reinterpret_cast<char *> (ptr); +} + +// This worker function is the entry point for each thread. + +static void * +worker (void *c) +{ + intptr_t count = reinterpret_cast<intptr_t> (c); + + ACE_thread_key_t key = ACE_OS::NULL_key; + int *ip = 0; + + // Make one key that will be available when the thread exits so that + // we'll have something to cleanup! + + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + for (intptr_t i = 0; i < count; i++) + { + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) in worker 1, key = %d, ip = %x\n", + key, + ip)); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::getspecific (key, (void **) &ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::setspecific (key, (void *) 0) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + delete ip; + + if (ACE_Thread::keyfree (key) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keyfree")); + + // Cause an error. + ACE_OS::read (ACE_INVALID_HANDLE, 0, 0); + + // The following two lines set the thread-specific state. + tss_error->error (errno); + tss_error->line (__LINE__); + + // This sets the static state (note how C++ makes it easy to do + // both). + tss_error->flags (count); + + { + ACE_hthread_t handle; + ACE_Thread::self (handle); + + // Use the guard to serialize access to printf... + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, printf_lock, 0); + +#if defined(linux) || defined(__OpenBSD__) + // @@ Normally the platform specific way to print a thread ID + // is encapsulated in Log_Msg.cpp, but for this small example + // we cannot (or do not want to) use ACE_Log_Msg. + ACE_OS::printf ("(%lu)", (unsigned long)handle); +#else + ACE_OS::printf ("(%u)", handle); +#endif /* ! linux */ + ACE_OS::printf (" errno = %d, lineno = %d, flags = %d\n", + tss_error->error (), + tss_error->line (), + tss_error->flags ()); + } + key = ACE_OS::NULL_key; + + if (ACE_Thread::keycreate (&key, cleanup) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keycreate")); + + ACE_NEW_RETURN (ip, + int, + 0); + + ACE_DEBUG ((LM_DEBUG, + "(%t) in worker 2, key = %d, ip = %x\n", + key, + ip)); + + if (ACE_Thread::setspecific (key, (void *) ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::getspecific (key, (void **) &ip) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + + if (ACE_Thread::setspecific (key, (void *) 0) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::setspecific")); + delete ip; + + if (ACE_Thread::keyfree (key) == -1) + ACE_ERROR ((LM_ERROR, + "(%t) %p\n", + "ACE_Thread::keyfree")); + } + + ACE_DEBUG ((LM_DEBUG, + "(%t) exiting\n")); + return 0; +} + +extern "C" void +handler (int signum) +{ + ACE_DEBUG ((LM_DEBUG, + "signal = %S\n", signum)); + ACE_Thread_Manager::instance ()->exit (0); +} + +int +ACE_TMAIN (int argc, ACE_TCHAR *argv[]) +{ + // The Service_Config must be the first object defined in main... + ACE_Service_Config daemon (argv[0]); + + int threads = argc > 1 ? ACE_OS::atoi (argv[1]) : 4; + intptr_t count = argc > 2 ? ACE_OS::atoi (argv[2]) : 10000; + + // Register a signal handler. + ACE_Sig_Action sa ((ACE_SignalHandler) (handler), SIGINT); + ACE_UNUSED_ARG (sa); + +#if defined (ACE_HAS_THREADS) + if (ACE_Thread_Manager::instance ()->spawn_n (threads, + ACE_THR_FUNC (&worker), + reinterpret_cast<void *> (count), + THR_BOUND | THR_DETACHED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, + "%p\n", + "ACE_Thread_Manager::spawn_n"), + -1); + + ACE_Thread_Manager::instance ()->wait (); +#else + worker ((void *) count); +#endif /* ACE_HAS_THREADS */ + return 0; +} + +#else +int +ACE_TMAIN (int, ACE_TCHAR *[]) +{ + ACE_ERROR_RETURN ((LM_ERROR, + "ACE doesn't support support threads on this platform (yet)\n"), + -1); +} +#endif /* ACE_HAS_THREADS */ |