$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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();
}