[cpp-threads] RE: volatile, memory models, threads

Peter Dimov pdimov at mmltd.net
Wed Mar 1 13:04:23 GMT 2006


Nick Maclaren wrote:
> "Peter Dimov" <pdimov at mmltd.net> wrote:
>>
>> Right, and it is the object representation that is the subject of
>> 3.9.3/1. "shall have the same representation and (alignment
>> requirements)." Object representation includes size (among other
>> things).
>
> Well, you may be right, but there is nothing that you have quoted that
> states (or even implies) that 3.9.3/1 refers to the object
> representation rather than the value representation.  My assertion is
> that it can be read either way, and the footnote strongly implies the
> latter.

Referring to the value representation would be meaningless in this context. 
The value representation of a const int x is completely invisible to a 
conforming program, because in order to inspect, for example, value bit 0, 
you need to write x & 1, and the lvalue to rvalue conversion drops the 
qualifiers, so you're actually looking at the value representation of the 
corresponding non-const int.

>> No. sizeof(x) is always the same when x is of type cv X, no matter
>> whether x is an argument, return value, or part of an array, and the
>> object representation of x is always the sequence of sizeof(x) ==
>> sizeof(X) bytes, starting from &x. It may well be the case that
>> physically, padding is inserted between x1 and x2 so that the
>> arguments occupy more space than they would otherwise, but this
>> doesn't change the representation of x1 or x2. A conforming program
>> is still allowed to inspect the object representation byte by byte
>> (or copy it into another object of the same type for PODs.)
>
> Firstly, I said size and I meant size.  The value returned by sizeof
> is NOT always the number of bytes occupied by an object, where that
> object is an argument or return value (or potentially, a member of a
> union).  The reason that can differ from the sizeof value is that it
> is not possible to have an array of any of those, and therefore no
> pointer arithmetic can be done on their addresses.
>
> The result of this is that the actual size of the object is never
> visible to a strictly conforming program, and so the implementations
> can use the "as if" rule.  Some early ones implemented sizeof to be
> the actual size of the object but, as far as I know, all current ones
> have corrected that to be the normal size of the object.
>
> Seriously.

This is all pretty basic knowledge, seriously. :-)

But why does it matter? The definition of an object is a sequence of N 
bytes, where N is returned by sizeof. A POD object is completely determined 
by these bytes, you can read them, encrypt them, decrypt them into another 
sequence of N bytes (with the appropriate alignment), and you'll have a copy 
of the original object back.

A compiler can align individual variables however it likes, true. So what?

> Secondly, where is what you claim above stated as a requirement?
>
> I have already SAID that it is implied by the ability to add
> qualifiers. I repeat my apology for creating unnecessary confusion,
> but I also repeat my assertion that the ONLY way in which
> cv-qualified types are required to have the same size (in the sizeof
> sense) is because such qualifiers can be added.  Drop that and there
> is NOTHING that I know of IN THE STANDARD stopping them from
> being different sizes.

3.9.3/1 seems pretty clear to me, sorry. :-)

It is actually pointer arithmetic that imposes the size requirement if we 
pretend that 3.9.3/1 doesn't. A language that doesn't have pointer 
arithmetic can have 'int const' with alignment 4 and 'int' with alignment 8, 
and every int* would be a valid int const*, but not vice versa.

But to get back to our atomics.

I agree with you that in the hypothetical syntax

    atomic int x;

'atomic' can't be a cv-qualifier if atomic ints have different alignment 
requirements or contain a per-object spinlock.

The library-like syntax of

    atomic<int> x;

solves the above problems by making atomic<int> a completely separate type.

For completeness, let me outline another alternative:

    int x;

with

    atomic_increment( &x );

failing to compile if x doesn't meet the alignment requirements for 
atomicity or placement (uncached memory). It would be the responsibility of 
the programmer to use whatever non-portable mechanisms are provided by the 
platform to ensure that x is aligned, placed appropriately in uncached 
memory, or doesn't share a cache line with another atomic.




More information about the cpp-threads mailing list