Boost logo

Boost :

Subject: Re: [boost] [thread] Can Boost.Thread use Boost.Atomic without falling on a compatibility issue?
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2013-01-13 12:51:53

On Sun, Jan 13, 2013 at 9:12 PM, Vicente J. Botet Escriba
<vicente.botet_at_[hidden]> wrote:
> Le 13/01/13 16:16, Andrey Semashev a écrit :
>> once_flag must always be statically initialized, that's the key feature
>> that
>> allows call_once to be thread-safe. In C++03 this can only be guaranteed
>> for
>> POD types. C++11 also includes constant initialization into static
>> initialization (i.e. when objects are initialized with constexpr
>> constructors). All other objects are initialized during dynamic
>> initialization, which is not thread-safe.
> Thanks for clarifications, I understand your concern. The non-POD once_flag
> implementation can not be used for static once_flag instances in a thread
> safe mode.
> Just for curiosity, from where comes the restriction that once_flag must
> always be statically initialized? Could you point me to the standard?

The standard only contains once_flag since C++11, and as you quoted
its definition, it uses constexpr default constructor. The fact that
it results in static initialization is outlined in 3.6.2/2.

As for C++03, I cannot point you to a particular paper that defines
once_flag; this is a matter of each particular implementation.
However, it is known that dynamic initialization is just as unsafe in
C++03 as it is in C++11, even more unsafe WRT function-local statics.
In 3.6.2/1 in C++03 it is stated that "Objects of POD types (3.9) with
static storage duration initialized with constant expressions (5.19)
shall be initialized before any dynamic initialization takes place.",
so one (if not the only one) way to implement once_flag safely is to
make it a POD type.

One thing still concerns me though with the C++11 code. The standard
specifies that once_flag as non-copyable. This is quite reasonable
when once_flag is used as described by the standard. OTOH,
Boost.Thread supports the following code for backward compatibility:

  static once_flag flag = BOOST_ONCE_INIT;

which expands to:

  static once_flag flag = once_flag();

Technically, this invokes the default constructor and then the copy
constructor. Compilers may be smart enough to optimize the copy away,
which explains why it compiles. But I'm not quite sure this is still a
constant initialization, especially considering the bug in clang (it
defines implicit constructor without constexpr). To be on the safe
side I would probably define a special explicit initializing
constructor marked with constexpr so that the initialization could
look like this:

  static once_flag flag = {0};

Boost list run by bdawes at, gregod at, cpdaniel at, john at