Как уже указывалось в нескольких других комментариях, volatile не связано с многопоточностью, поэтому здесь следует использовать , а не . Однако причина, по которой volatile работает лучше, чем у atmoi c, заключается просто в том, что при использовании volatile ++n
означает простую загрузку, в c - инструкции по сохранению, а при использовании атома c - более дорогой. lock xadd
(при условии, что вы компилируете для x86).
Но так как это только очередь с одним читателем для одного читателя, вам не нужны дорогие операции чтения-изменения-записи:
struct queue {
queue() {
tail = head = &reserved;
n = 0;
}
void push(item *it) {
tail->next = it;
tail = it;
auto new_n = n.load(std::memory_order_relaxed) + 1;
n.store(new_n, std::memory_order_release);
}
item* pop() {
while (n.load(std::memory_order_acquire) == used);
++used;
head = head->next;
return head;
}
item reserved;
item *tail, *head;
int used = 0;
std::atomic <int> n;
}
Это должно работать так же хорошо, как и изменчивая версия. Если загрузка получения в pop
«видит» значение, записанное релизом хранилища в push
, эти две операции синхронизируются друг с другом, устанавливая тем самым требуемое отношение «происходит до».