Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2002-08-07 09:30:48


From: Andrew J Bromage <ajb_at_[hidden]>
> class something
> {
> public:
> const expensive_data&
> get_expensive()
> {
> m_once.call_once(&make_expensive_data);
> return *m_expensive;
> }
> something(const other_data& other)
> : m_other(other)
> {
> }
> private:
> boost::once m_once;
> std::auto_ptr<expensive_data> m_expensive;
> other_data m_other;
> void
> make_expensive_data()
> {
> m_expensive = new expensive_data(m_other);
> }
> };
>
> Moreover (and this is what makes it tricky), I want to do it with as
> little mutex contention as possible. In particular I want to avoid
> obtaining a lock when get_expensive() is called after the expensive
> data has been created.

Is it that tricky? If there was a static pointer that was initialized to zero
and was set to the address of the initialized object once ready, then a simple
test of the pointer would indicate whether a synchronized check and possibly
initialization is needed. Of course you need a static pointer for each object
you want call_once to work with, but templates can help there, can't they? That
is, we could have the compiler generate a new template specialization for each
call_once object created, and those specializations can create the static
pointer.

This approach means that near initialization time, call_once may do some locking
in multiple threads as they vie to be the one to initialize the data and wait
for its initialization. After initialization, no locking would be needed since
the pointer will then be non-null. IOW, it isn't quite the ideal you specified,
but it's pretty close.

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk