[cpp-threads] Update

Peter Dimov pdimov at mmltd.net
Mon Jul 10 22:50:39 BST 2006


Boehm, Hans wrote:

> The high level interface does seem to buy you some useful properties:
>
> 1) Things like double-checked locking work with just a declaration
> change, as they do in Java.  My impression is that some people
> perceive this as close to a requirement.
>
> 2) It can be directly applied to struct of bit-fields and the like.
>
> 3) Parameterization w.r.t. ordering constraints, which can reduce the
> amount of required library code.

Perhaps it does buy some people something; I'm not disputing that. I have no 
interest in it, though. It doesn't seem to buy me anything. :-)

>> * This is how I think atomic_cas needs to be specified:
>>
>> bool atomic_cas( T * addr, T * oldv, T newv );
>>
>> Effects: if *addr contains the value *oldv, atomically
>> updates *addr to contain newv and returns true, otherwise
>> stores *addr in *oldv and returns false. When T is not a
>> built-in type, performs a bitwise comparison.

> Clearly adding documentation is good.
>
> I have mixed feelings about making oldv a pointer.  I don't have a
> good feeling as to how good compilers are at register-allocating
> variables whose address has been taken.  I would guess that if this
> is implemented as in-line assembly code, they won't.  I suspect that
> at least initially this version will result in slower
> implementations, but I don't currently have any data.

This variation does indeed result in "slower" assembly code on some 
platforms, but not because of the pointer, but because of the bool return 
value. The "slower" assembly code doesn't affect performance in a measurable 
way according to my not-particularly-extensive tests, though.

I have an argument in support of this primitive, though. Consider a 
hypothetical platform where int is 36 bits, only 32 of which are value bits, 
and consider this loop:

for( ;; )
{
    int oldv = *p;
    if( atomic_cas( p, oldv, newv ) == oldv ) return true; // success
}

Since only the value bits matter (and are affected by the assignment), and 
since CAS typically performs a full bitwise comparison, there is no 
guarantee that this loop will ever end.

In contrast:

int oldv = *p;

for( ;; )
{
    if( atomic_cas( p, &oldv, newv ) ) return true; // success
}

Even though the initial iteration may fail for the above reason, CAS returns 
in oldv the exact contents of *p, including any padding, and the subsequent 
iteration will succeed.

>> * I'd really like to see
>> atomic_decrement_<order1,nonzero>_<order2,zero>, or at least
>> atomic_decrement_release_acquire. This primitive is essential
>> for correct reference counting. The closest the current
>> proposal has is atomic_fetch_add_ordered. It may be argued
>> that it's close enough for all contemporary platforms.

> I think the more precise version would be a tough sell.  My impression
> is that there is already a lot of concern that the current version is
> too complicated.

I'm not sure that I want to sell anything to anybody yet. My interest is 
mostly because Boost needs an atomics library backbone to support the 
various reference count and mutex implementations, so it would be nice if I 
could just implement the current proposal, or more specifically, its 
low-level part. I have no use for the high-level part at the moment. 




More information about the cpp-threads mailing list