|
Boost : |
From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2006-10-07 14:11:12
Here's a win32-only static once_init implementation. This could be used as a
general purpose static-init template, or as a basis for making boost::mutex
work both as a static or non-static object, with a default constructor.
Comments please,
Anthony
-- Anthony Williams Software Developer Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk ////////// #include <cstring> #include <cstddef> #include "boost/aligned_storage.hpp" #include "boost/thread/win32/interlocked_read.hpp" #include <boost/static_assert.hpp> #include <boost/thread/win32/thread_primitives.hpp> #include <boost/detail/interlocked.hpp> #include "boost/thread/mutex.hpp" #include <windows.h> #include <iostream> #include "boost/thread/thread.hpp" #ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::strlen; using ::memcpy; using ::ptrdiff_t; } #endif template<typename T> struct once_init { once_init() { init_once(); } ~once_init() { (*this)->~T(); CloseHandle(init_event); } void lazy_init() { if(!::boost::detail::interlocked_read(&init_event)) { init_once(); } } T* operator->() { lazy_init(); return reinterpret_cast<T*>(data.address()); } private: void* init_event; boost::aligned_storage<sizeof(T)> data; BOOST_STATIC_CONSTANT(unsigned,name_fixed_length=48); BOOST_STATIC_CONSTANT(unsigned,event_name_length=name_fixed_length+sizeof(void*)*2+sizeof(unsigned long)*2+1); template <class I> void int_to_string(I p, char* buf) { unsigned i=0; for(; i < sizeof(I)*2; ++i) { buf[i] = 'A' + static_cast<char>((p >> (i*4)) & 0x0f); } buf[i] = 0; } void create_event_name(char (&name)[event_name_length]) { static const char fixed_name[]="{F21E1417-EF70-4665-9758-5DBC70AE2FCC}-init-flag"; BOOST_STATIC_ASSERT(sizeof(fixed_name) == (name_fixed_length+1)); std::memcpy(name,fixed_name,sizeof(fixed_name)); BOOST_ASSERT(sizeof(name) == std::strlen(name) + sizeof(void*)*2 + sizeof(unsigned long)*2 + 1); BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t)); int_to_string(reinterpret_cast<std::ptrdiff_t>(this), name + name_fixed_length); int_to_string(GetCurrentProcessId(), name + name_fixed_length + sizeof(void*)*2); BOOST_ASSERT(sizeof(name) == std::strlen(name) + 1); } void init_once() { char event_name[event_name_length]; create_event_name(event_name); void* const event=CreateEventA(NULL,true,false,event_name); BOOST_ASSERT(event); if(GetLastError()==ERROR_ALREADY_EXISTS) { WaitForSingleObject(event,BOOST_INFINITE); } else { new(reinterpret_cast<T*>(data.address())) T(); BOOST_INTERLOCKED_EXCHANGE_POINTER(&init_event,event); SetEvent(event); } } }; struct A { A() { std::cout<<GetCurrentThreadId()<<"initialize "<<this<<std::endl; Sleep(1000); } ~A() { std::cout<<GetCurrentThreadId()<<"destroy "<<this<<std::endl; } void f() { std::cout<<GetCurrentThreadId()<<"f "<<this<<std::endl; } int i; }; void f() { static once_init<A> a; a->f(); } int main() { boost::thread t1(f); boost::thread t2(f); t2.join(); t1.join(); }
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk