summaryrefslogtreecommitdiff
path: root/ACE/examples/Threads/thread_specific.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/examples/Threads/thread_specific.cpp')
-rw-r--r--ACE/examples/Threads/thread_specific.cpp226
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 */