Subject: Re: [boost] [lockfree] _ENABLE_ATOMIC_ALIGNMENT_FIX for VS 2015 Update 2
From: Tim Blechmann (tim_at_[hidden])
Date: 2016-05-10 13:35:45
> While running Boost.Lockfree's tests, one of our compiler devs encountered the following failure:
> c:\wcfb01\binaries\x86chk\inc\atomic(659): error C2338: You've instantiated std::atomic<T> with sizeof(T) equal to 2/4/8 and alignof(T) < sizeof(T). Before VS 2015 Update 2, this would have misbehaved at runtime. VS 2015 Update 2 was fixed to handle this correctly, but the fix inherently changes layout and breaks binary compatibility. Please define _ENABLE_ATOMIC_ALIGNMENT_FIX to acknowledge that you understand this, and that everything you're linking has been compiled with VS 2015 Update 2 (or later).
> c:\wcfb01\binaries\x86chk\inc\atomic(669): note: see reference to class template instantiation 'std::_Atomic_base<_Ty,4>' being compiled
> e:\boost\boost\boost\lockfree\detail\freelist.hpp(608): note: see reference to class template instantiation 'std::atomic<boost::lockfree::detail::tagged_index>' being compiled
> e:\boost\boost\boost\lockfree\detail\freelist.hpp(609): note: see reference to class template instantiation 'boost::lockfree::detail::fixed_size_freelist<T,NodeStorage>' being compiled
> call "C:\WCFB01\binaries\x86chk\bin\i386\vcvarsall.bat" x86 >nul
> cl /Zm800 -nologo @"..\bin.v2\libs\lockfree\test\freelist_test.test\msvc-latest\debug\threading-multi\freelist_test.obj.rsp"
> ...failed compile-c-c++ ..\bin.v2\libs\lockfree\test\freelist_test.test\msvc-latest\debug\threading-multi\freelist_test.obj...
> with the following type:
> class tagged_index
> typedef boost::uint16_t tag_t;
> typedef boost::uint16_t index_t;
> index_t index;
> tag_t tag;
> This is by design - your tagged_index has align 2, size 4, triggering the need for my atomic alignment fix. As the static_assert advises, your code needs to define _ENABLE_ATOMIC_ALIGNMENT_FIX in order to pass.
> If this has already been fixed in 1.61.0, then that's great (I haven't checked).
giving it a second thought, my interpretation of the standard suggests
that that it is valid code that the compiler should accept.
the standard (or n3290, which i have on my machine) tells me:
> There is a generic class template atomic<T>. The type of the template argument T shall be trivially copy assignable and bitwise equality comparable.
i cannot find any wording which requires specific alignment requirements
for T. imho this is for a good reason: the type T might not be part of
your codebase, but coming from the API of a third-party library.
even if tagged_index is 2-byte aligned, it it would be perfectly valid
to use atomic<tagged_index>. the implementation should work, it is just
not guaranteed that an instance is_lock_free(). i suppose that this is
exactly the reason why atomic::is_lock_free() is an instance method and
not a class method: depending on the address of the instance, the
implementation could be lock-free or not. the code path which is not
lockfree might use a spinlock pool, located in the run-time library.
this would be allowed because:
> [Note: Operations that are lock-free should also be address-free. That is, atomic operations on the same memory location via two different addresses will communicate atomically. The implementation should not depend on any per-process state. This restriction enables communication by memory that is mapped into a process more than once and by memory that is shared between two processes. end note ]
maybe something changed in the wording of the standard, but from what i
can tell this change to msvc will reject valid code.
so my suggestion is the following:
* make atomic<T> lock-free depending on the address of the instance, use
whatever fallback mechanism you have to emulate non-lock-free atomics.
* using a spinlock-pool in the run-time library for emulating blocking
atomic<>s to ensure that sizeof(T) == sizeof(atomic<T>). afaict the
standard doesn't impose any restrictions on this, but leaves this open
to the implementation.
* issue a warning that T should be properly aligned to ensure that
atomic<T> will always be lock-free.
afaict you would then end up with a rather standard-compliant
implementaton of atomic<T>.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk