Boost logo

Boost :

Subject: Re: [boost] [Boost.utility]
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2010-01-27 17:47:07


----- Original Message -----
From: "Andrew Chinkoff" <achinkoff_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, January 27, 2010 10:48 PM
Subject: Re: [boost] [Boost.utility]

>
>
> Ok, I see. I would try to explain.
>
> Let us look at pseudo code:
<snip>
> *** BEGIN EXPLANATION ***
> Let us imagine that boost::call_once has approximately this implementation
> (in pseudo code):
>
> call_once(function foo)
> {
> if(!called)
> {
> Locker locker;
> if(!called)
> {
> called = true;
> foo(); (1)
> }
> }
> }
>
> If you insert foo code at line (1), you will see the cascade of nested
> blocks like this:
>
> if(!flag1)
> {
> Locker locker;
> if(!flag2) // "Double Check Locking"
> {
> Locker locker;
> if(!flag3) // "Triple Check Locking"
> {
> Locker locker;
> ...
> ...
> ...
> foo();
> ...
> ...
> ...
> }
> }
> }
>
<snip>
> I assume that boost::call_once does so:
>
> if(ATOMIC(!flag1)) // (2)
> {
> Locker locker;
> ...
> }
>
> I would like to ask Boost.Commutiny - is my assumption at line (2) the true?
> *** END OF EXPLANATION ***
>
> P.S. 1: Sorry for verbosity and complexity, if so.
>

Andrew, you don't need to make supossitions on how call_once works. Just see the current implementation for Posix systems (extracted from boost/thread/posinx/once.hpp):

    template<typename Function>
    void call_once(once_flag& flag,Function f)
    {
        static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
        static boost::uintmax_t const being_initialized=uninitialized_flag+1;
        boost::uintmax_t const epoch=flag.epoch;
        boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
        
        if(epoch<this_thread_epoch)
        {
            pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);

            while(flag.epoch<=being_initialized)
            {
                if(flag.epoch==uninitialized_flag)
                {
                    flag.epoch=being_initialized;
                    try
                    {
                        pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
                        f();
                    }
                    catch(...)
                    {
                        flag.epoch=uninitialized_flag;
                        BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
                        throw;
                    }
                    flag.epoch=--detail::once_global_epoch;
                    BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
                }
                else
                {
                    while(flag.epoch==being_initialized)
                    {
                        BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
                    }
                }
            }
            this_thread_epoch=detail::once_global_epoch;
        }
    }

Now you can make a concrete request on a concrete implementation.

Best,
Vicente


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