Re: Confused about a thread-safe singleton example.
Here is a working example code for MSVC++ 8>:
______________________________________________________________________________
/* POSIX Threads (pthread-win32) / MSVC Singleton
____________________________________________________________________*/
#include <pthread.h>
#include <cassert>
#include <cstdio>
#if defined(_MSC_VER)
# define DECLSPEC_THREAD static __declspec(thread)
# define DEFSPEC_THREAD __declspec(thread)
# define DECLSPEC_CDECL __cdecl
# define DEFSPEC_CDECL __cdecl
#else
# define DECLSPEC_THREAD __thread
# define DEFSPEC_THREAD
# define DECLSPEC_CDECL __attribute__((cdecl))
# define DEFSPEC_CDECL __attribute__((cdecl))
#endif
namespace posix {
namespace thread {
template<typename T>
class once {
DECLSPEC_THREAD T* g_tls;
static T* g_instance;
static pthread_once_t g_once;
static void DECLSPEC_CDECL prv_init();
public:
static T& instance();
};
template<typename T>
DEFSPEC_THREAD T* once<T>::g_tls = NULL;
template<typename T>
T* once<T>::g_instance = NULL;
template<typename T>
pthread_once_t once<T>::g_once = PTHREAD_ONCE_INIT;
template<typename T>
void DECLSPEC_CDECL once<T>::prv_init() {
static T g_obj;
assert(! g_instance);
g_instance = &g_obj;
std::printf("INSTANCE SLOW-PATH STATIC INIT! <(%p)->g_instance>\n",
(void*)g_instance);
}
template<typename T>
T& once<T>::instance() {
if (! g_tls) {
int const status = pthread_once(&g_once, prv_init);
if (status) {
assert(! status);
throw;
}
g_tls = g_instance;
if (! g_tls) {
assert(g_tls);
throw;
}
std::printf("INSTANCE SLOW-PATH! <(%p)->g_tls == (%p)->g_instance>\n",
(void*)g_tls, (void*)g_instance);
} else {
std::printf("INSTANCE FAST-PATH! <(%p)->g_tls == (%p)->g_instance>\n",
(void*)g_tls, (void*)g_instance);
assert(g_tls == g_instance);
}
return *g_tls;
}
// abstract thread
class thread_base {
pthread_t m_handle;
virtual void on_active() = 0;
static void* DEFSPEC_CDECL prv_active(void* state) {
static_cast<thread_base*>(state)->on_active();
return 0;
}
public:
virtual ~thread_base() = 0;
void active_run() {
pthread_create(&m_handle, NULL, prv_active, this);
}
void active_join() {
pthread_join(m_handle, NULL);
}
};
thread_base::~thread_base() {}
}} // namespace posix::thread
// active helper
template<typename T>
struct active : public T {
active() : T() {
active_run();
}
template<typename P1>
active(P1 p1) : T(p1) {
active_run();
}
~active() {
active_join();
}
};
/* Sample Application
____________________________________________________________________*/
// abstract the namespace
namespace mythread = posix::thread;
template<unsigned TYPE>
struct foo {
foo() {
std::printf("(%p)->foo<%u>::foo()\n", (void*)this, TYPE);
}
~foo() {
std::printf("(%p)->foo<%u>::~foo()\n", (void*)this, TYPE);
std::puts("hit <ENTER> to continue...");
std::fflush(stdout);
std::getchar();
}
void do_something(unsigned thread_id) {
std::printf("(%p)->foo<%u>::do_something() called by (%u)\n",
(void*)this, TYPE, thread_id);
}
};
class worker : public mythread::thread_base {
unsigned const m_id;
void on_active() {
std::printf("(%p)->worker(%u)::on_active() - enter\n", (void*)this,
m_id);
for (unsigned i = 0; i < 10; ++i) {
if (! (i % 2)) {
mythread::once<foo<0> >::instance().do_something(m_id);
mythread::once<foo<1> >::instance().do_something(m_id);
mythread::once<foo<2> >::instance().do_something(m_id);
mythread::once<foo<3> >::instance().do_something(m_id);
mythread::once<foo<3> >::instance().do_something(m_id);
mythread::once<foo<2> >::instance().do_something(m_id);
mythread::once<foo<1> >::instance().do_something(m_id);
mythread::once<foo<0> >::instance().do_something(m_id);
} else {
mythread::once<foo<4> >::instance().do_something(m_id);
mythread::once<foo<5> >::instance().do_something(m_id);
mythread::once<foo<6> >::instance().do_something(m_id);
mythread::once<foo<7> >::instance().do_something(m_id);
mythread::once<foo<7> >::instance().do_something(m_id);
mythread::once<foo<6> >::instance().do_something(m_id);
mythread::once<foo<5> >::instance().do_something(m_id);
mythread::once<foo<4> >::instance().do_something(m_id);
}
}
std::printf("(%p)->worker(%u)::on_active() - exit\n", (void*)this,
m_id);
}
public:
worker(unsigned const id) : m_id(id) {}
};
int main(void) {
{
active<worker> workers[] = { 123, 456, 789, 213, 645, 978, 543, 1024 };
}
return 0;
}
______________________________________________________________________________
This should compile fine. You need the `pthread-win32' library for this to
work on windows. No reason why this would not work on pure POSIX system with
compiler that had similar extensions.