Consider the following code:
struct payload
{
std::atomic< int > value;
};
std::atomic< payload* > pointer( nullptr );
void thread_a()
{
payload* p = new payload();
p->value.store( 10, std::memory_order_relaxed );
std::atomic_thread_fence( std::memory_order_release );
pointer.store( p, std::memory_order_relaxed );
}
void thread_b()
{
payload* p = pointer.load( std::memory_order_consume );
if ( p )
{
printf( "%d\n", p->value.load( std::memory_order_relaxed ) );
}
}
Does C++ make any guarantees about the interaction of the fence in thread a with the consume operation in thread b?
I know that in this example case I can replace the fence + atomic store with a store-release and have it work. But my question is about this particular case using the fence.
Reading the standard text I can find clauses about the interaction of a release fence with an acquire fence, and of a release fence with an acquire operation, but nothing about the interaction of a release fence and a consume operation.
Replacing the consume with an acquire would make the code standards-compliant, I think. But as far as I understand the memory ordering constraints implemented by processors, I should only really require the weaker 'consume' ordering in thread b, as the memory barrier forces all stores in thread a to be visible before the store to the pointer, and reading the payload is dependent on the read from the pointer.
Does the standard agree?
No comments:
Post a Comment