C++ Logo

std-discussion

Advanced search

Re: atomic_ref::required_alignment usefulness

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Mon, 10 Feb 2020 11:44:42 +0300
On 2020-02-10 09:41, Thiago Macieira wrote:
> On Sunday, 9 February 2020 06:15:44 PST Andrey Semashev via Std-Discussion
> wrote:
>> Hi,
>>
>> As specified in N4849, atomic_ref<T>::required_alignment is:
>>
>> The alignment required for an object to be referenced by an atomic
>> reference, which is at least alignof(T).
>>
>> This wording does not give provision as to whether this alignment is
>> strict enough so that atomic_ref<T> is lock-free (provided that it can
>> be lock-free at all). At the same time, atomic_ref<T> does not provide a
>> constant for the alignment that guarantees lock-free operations (again,
>> provided that they can be lock-free). Let's call this missing constant
>> recommended_alignment.
>>
>> Is my understanding correct? If so, it seems like required_alignment is
>> rather useless, as there seems to be no reason to make it anything other
>> than alignof(T). Why is recommended_alignment, which is much more
>> useful, missing?
>
> I'm not understanding why you want two constants, instead of just one.

It's not that I want two constants. I want a different one from what is
described in the standard.

> Can you
> help by giving an example of an architecture where the two constants would be
> different. Please specify whether that architecture is real or hypothetical.
>
> The example that comes to me is i386, where alignof(8 bytes) is often 4, but
> atomic access requires them to be aligned to 8. That is,
> atomic_ref<long long>::required_alignment > alignof(long long)
>
> PS: the hardware doesn't actually require this alignment, but please shoot any
> code that tries to do unaligned atomic access with extreme prejudice.

Yes, x86 is one of such architectures, as is any CAS-based architectures
I'm aware of. The example is mentioned in the standard:
atomic_ref<complex<double>>. Assuming double is 64-bit and
complex<double> is a 128-bit structure, it must be aligned to 16 bytes
for atomic CAS(*), but alignof(complex<double>) is 8.

As a user of atomic_ref, when I introduce a complex<double> variable
that I plan to access atomically, I might want to align it properly,
like this:

   alignas(atomic_ref<complex<double>>::required_alignment)
     complex<double> var;
   atomic_ref<complex<double>> ref(var);

But given the definition of required_alignment in the standard, this
code does not guarantee that ref.is_lock_free() will be true. An
implementation where required_alignment is 8 and ref is implemented with
a lock pool is allowed by the standard. Even if such atomic_ref
implementation supports lock-free operations starting at alignment of 16.

What I want is a constant that would be have the value of 16 in this
case. I.e. the alignment that would make atomic_ref lock-free, if it can
be at all for an object of such size. If it can't, let it be equal to
alignof(T).

(*) If it is not aligned, atomicity is not guaranteed on x86. I think, a
hardware exception is generated, which can be handled by the kernel. The
exception handler may emulate the atomic CAS (at terrible performance
cost) or it may kill the process with SIGBUS. For our purposes of
atomic_ref, let's assume this is not the desired behavior and unaligned
atomics are banned.

Received on 2020-02-10 02:47:24