Boost logo

Boost :

Subject: Re: [boost] [thread] C++11 once_flag enabled when constexpr is not available
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2013-03-05 08:01:56


On Tue, Mar 5, 2013 at 4:31 PM, Vicente J. Botet Escriba
<vicente.botet_at_[hidden]> wrote:
> Le 22/02/13 23:49, Andrey Semashev a écrit :
>
>> Hi, Vicente!
>>
>> I see you applied my patch for call_once but you seem to forgot to disable
>> the
>> C++11 call_once interface when the compiler does not support constexpr.
>> Was
>> that intentional or you just missed it?
>>
>> Anyway, please find the patch attached.
>>
> Hi Andrey,
>
> In your patch you say
>
> +// For C++11 call_once interface the compiler MUST support constexpr.
> +// Otherwise once_flag would be initialized during dynamic initialization
> stage, which is not thread-safe.
>
>
> I'm not an expert on the C++11 wording. Could you elaborate why once_flag
> would be initialized during dynamic initialization stage?

It's covered in 3.6.2/2. In particular:

<quote-C++11>
Variables with static storage duration (3.7.1) or thread storage
duration (3.7.2) shall be zero-initialized (8.5)
before any other initialization takes place.

Constant initialization is performed:

...

— if an object with static or thread storage duration is initialized
by a constructor call, if the constructor is
a constexpr constructor, if all constructor arguments are constant
expressions (including conversions),
and if, after function invocation substitution (7.1.5), every
constructor call and full-expression in
the mem-initializers and in the brace-or-equal-initializers for
non-static data members is a constant
expression;
— if an object with static or thread storage duration is not
initialized by a constructor call and if every
full-expression that appears in its initializer is a constant expression.

Together, zero-initialization and constant initialization are called
static initialization; all other initialization is
dynamic initialization. Static initialization shall be performed
before any dynamic initialization takes place.
</quote-C++11>

The C++11 once_flag has constexpr constructor, which makes it suitable
for constant initialization and thread-safe. Now, if the compiler does
not support constexpr, and once_flag still has non-trivial constructor
(that's the case with Boost.Thread implementation), the once_flag
initialization is performed at dynamic initialization. The only way to
make it statically initialized is to remove the constructor and
initialize it as an aggregate. It will then fall under the second
quoted bullet.

If the compiler implements C++03 then aggregate initialization is the
only solution. Under 3.6.2/1:

<quote-C++03>
Objects with static storage duration (3.7.1) shall be zero-initialized
(8.5) before any other initialization
takes place. Zero-initialization and initialization with a constant
expression are collectively called static
initialization; all other initialization is dynamic initialization.
Objects of POD types (3.9) with static stor-
age duration initialized with constant expressions (5.19) shall be
initialized before any dynamic initial-
ization takes place.
</quote-C++03>

The fact that aggregate initialization is performed in the static
initialization stage is warranted by 8.5.1/14:

<quote-C++03>
When an aggregate with static storage duration is initialized with a
brace-enclosed initializer-list, if all the
member initializer expressions are constant expressions, and the
aggregate is a POD type, the initialization
shall be done during the static phase of initialization (3.6.2)
</quote-C++03>


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