[cpp-threads] Comments on N2324
Paul E. McKenney
paulmck at linux.vnet.ibm.com
Mon Jul 16 22:23:26 BST 2007
Hello!
A few comments on N2324.
Thanx, Paul
o "Memory Model Interactions" -- need to call out support of
existing practice as a goal that guides the standard.
o "Memory Model Interactions" -- on data dependencies, specific
comments on or objections to the proposals in N2260?
o "Remaining Issues" -- "This issue as that any function will
often be inappropriate": "as" should be "is".
o "Atomic Operations" -- The swap, compare-and-swap, and fetch-and-*
operations are defined to be "in the sense of synchronizes with".
This should be the case only when they are non-relaxed.
o "Atomic Operations" -- s/stive/strive/ or define the term
"stive". Ditto s/operatoins/operations/.
o "Atomic Operations" -- "volatility is preserved when applying
these operations to volatile objects. It does not mean that
operatoins on non-volatile objects become volatile." Does
this mean that the compiler is permitted to merge successive
atomic operations on a given atomic variable? Or are atomics
implicitly volatile?
o "Atomic Operations"/"atomic_address" -- why not fetch-and-and,
fetch-and-or, and fetch-and-xor? I can see the point of avoiding
these operation on the partial pointer specializations, but
if you are working with raw addresses anyway...
o "Atomic Types" -- the fence operation is just using the underlying
object as an ID, it seems. But...
o Does a fence operation on a given variable synchronize
with a load_acquire or store_release operation on
that same variable? If so, what does this mean?
o x.fence(memory_order_relaxed) is a no-op, correct?
o "Lock-Free" -- "The clear and test-and-set operations must be
lock-free, and hence address-free." What does it mean for
a test-and-set operation to be address-free? It has to do
the test-and-set on -some- address or another, right?
Also the "clear" in this sentence is shorthand for
"test-and-clear"? Or "atomic_flag_clear"?
o "Synopsis" -- I confess, I have no idea what the "delete"
means in the following syntax:
atomic_flag& operator =( const atomic_flag& ) = delete;
Force subtypes to define this member function? Make it be
the "delete" operator? Prohibit subtypes from defining
this operator? Something else entirely?
o "Flag" -- This isn't supposed to be a functional example that
accomplishes some specific task, correct?
o "Lazy Initialization" -- The "lazy_example_fence_cpp()" function
seems to leave out a fence. I believe that the code should
instead be as follows:
int lazy_example_fence_cpp( void )
{
if ( lazy_ready.load( memory_order_relaxed ) )
lazy_ready.fence( memory_order_acquire );
else if ( lazy_assigned.swap( true, memory_order_relaxed ) ) {
while ( ! lazy_ready.load( memory_order_relaxed ) );
lazy_ready.fence( memory_order_acquire );
} else {
lazy_value = 42;
lazy_ready.fence( memory_order_release );
lazy_ready.store( true, memory_order_relaxed );
}
return lazy_value;
}
That said, the following from N2262 seems more straightforward
to me:
int lazy_example_fence_cpp( void )
{
if ( lazy_ready.load( memory_order_relaxed ) )
acquire_memory_fence();
else if ( lazy_assigned.swap( true, memory_order_relaxed ) ) {
while ( ! lazy_ready.load( memory_order_relaxed ) );
acquire_memory_fence();
} else {
lazy_value = 42;
release_memory_fence();
lazy_ready.store( true, memory_order_relaxed );
}
return lazy_value;
}
Of course, in this case, the variable-based non-fence approach
is simpler -- but converting existing code would benefit from
variable-free fences.
o "Integer" -- given that "taul" is non-volatile, is the compiler
permitted to merge the last six statements of this function?
taul = x;
taul += 1;
taul ^= 4;
taul -= taul++;
taul |= --taul;
taul &= 7;
o "List Insert" -- these functions fail when inserting concurrently
because the value of the head pointer is never re-fetched.
Here is a suggested modification:
void list_example_strong( data* item )
{
node* candidate = new node;
candidate->value = item;
do {
candidate->next = head;
} while ( ! head.compare_swap( candidate->next, candidate ) );
}
void list_example_weak( struct data* item )
{
node* candidate = new node;
candidate->value = item;
do {
candidate->next = head.load( memory_order_relaxed );
} while ( ! head.compare_swap( candidate->next, candidate,
memory_order_release ) );
}
More information about the cpp-threads
mailing list