Что-то очень странное появилось во время дезинфекции нити предлагаемого boost:: concurrent_unordered_map и рассказанного в этом сообщении в блоге. Короче говоря, bucket_type выглядит так:
struct bucket_type_impl
{
spinlock<unsigned char> lock; // = 2 if you need to reload the bucket list
atomic<unsigned> count; // count is used items in there
std::vector<item_type, item_type_allocator> items;
bucket_type_impl() : count(0), items(0) { }
...
Тем не менее, нить sanitiser утверждает, что между конструкцией bucket_type и ее первым использованием существует расы, в частности, когда загружается атом отсчета. Оказывается, если вы инициализируете std:: atomic < > через свой конструктор что инициализация не является атомарной, и поэтому местоположение памяти не выделяется атомом и поэтому не отображается к другим потокам, что противоречит интуиции, учитывая, что это атомный, и что большинство атомных операций по умолчанию - memory_order_seq_cst. Поэтому вы должны явно создать хранилище релизов после построения, чтобы инициализировать атом, со значением, видимым для других потоков.
Есть ли какая-то чрезвычайно насущная причина, почему std:: atomic с конструктором, потребляющим значение, не инициализирует себя семантикой выпуска? Если нет, я думаю, что это дефект библиотеки.
Изменить: Ответ Джонатана лучше для истории о том, почему, но ecatmur ответит на ссылки на сообщение об ошибке Alastair по этому вопросу и как он был закрыт, просто добавив примечание к предложениям по строительству нет видимости для других потоков. Поэтому я вручу ответ ecatmur. Спасибо всем, кто ответил, я думаю, что понятно, что нужно спросить о дополнительном конструкторе, он, по крайней мере, будет выделяться в документации, что есть что-то необычное в конструкторе потребления стоимости.
Изменить 2: Я закончил тем, что поднял это как недостаток на языке С++ с комитетом, а Ханс Бем, который возглавляет часть Concurrency, считает, что это не проблема по следующим причинам:
-
Никакой существующий компилятор С++ в 2014 году не рассматривает, как потреблять. Поскольку в коде реального мира вы никогда не перейдете атом к другому потоку, не пройдя какой-либо выпуск/приобретать, инициализация атома будет видна для всех потоков с использованием атома. Я думаю, это прекрасно, пока компиляторы не догонят, и до этого Thread Sanitiser предупредит об этом.
-
Если вы выполняете несогласованную покупку-получение-релиз, как я, (я использую атом-релиз-внутри-блокировки/потребления-вне-блокировки, чтобы умозрительно избегать использования спин-блокировки, освобождающей релиз, где это было необязательно) тогда вы достаточно большой мальчик, чтобы знать, что вы должны вручную хранить выпускные атомы после строительства. Это, вероятно, справедливая точка.