Рассмотрим следующий код:
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 ) );
}
}
Делает ли C ++ какие-либо гарантии взаимодействия ограды в потоке a с операцией потребления в потоке b?
Я знаю, что в этом примере я могу заменить магазин fence + atomic store-release и заставить его работать. Но мой вопрос об этом конкретном случае использования забора.
Читая стандартный текст, я могу найти предложения о взаимодействии ограничителя освобождения с ограничителем получения и разделительного барьера с операцией получения, но ничего не говорится о взаимодействии ограничителя освобождения и операции потребления.
Думаю, замена потребителя на приобретение сделает код совместимым со стандартами. Но насколько я понимаю ограничения упорядочения памяти, реализованные процессорами, мне действительно нужно только более слабое упорядочение «потреблять» в потоке b, так как барьер памяти заставляет все хранилища в потоке a быть видимыми до сохранения для указателя, и чтение полезной нагрузки зависит от чтения из указателя.
Стандарт согласен?
Ваш код работает.
Я знаю, что в этом примере я могу заменить магазин fence + atomic store-release и заставить его работать. Но мой вопрос об этом конкретном случае использования забора.
Забор с расслабленной атомной операцией сильнее чем соответствовала атомная операция. Например. (от http://en.cppreference.com/w/cpp/atomic/atomic_thread_fence, Заметки):
В то время как атомарная операция освобождения хранилища препятствует тому, чтобы все предыдущие записи прошли мимо выпуска хранилища, atomic_thread_fence с memory_order_release порядок не позволяет всем предыдущим записям проходить мимо всех последующих хранилищ.