Я играю с алгоритмами без блокировок в C и C ++ и недавно наткнулся на поведение, которое я не совсем понимаю. Если у вас есть следующий код, его запуск даст вам что-то вроде
читатель начал писатель начал иттерс = 79895047, меньше = 401131, экв = 48996928, больше = 30496988
не являются std::atomics
как ожидается, будет последовательно последовательным? Если так, то почему читатель иногда видит b
обновляется раньше a
? Я также безуспешно пытался делать различные трюки с заборами памяти. Полный скомпилированный код можно увидеть на https://github.com/akamaus/fence_test
Что не так с примером?
std::atomic<uint> a(0);
std::atomic<uint> b(0);
volatile bool stop = false;
void *reader(void *p) {
uint64_t iter_counter = 0;
uint cnt_less = 0,
cnt_eq = 0,
cnt_more = 0;
uint aa, bb;printf("reader started\n");
while(!stop) {
iter_counter++;
aa = a.load(std::memory_order_seq_cst);
bb = b.load(std::memory_order_seq_cst);
if (aa < bb) {
cnt_less++;
} else if (aa > bb) {
cnt_more++;
} else {
cnt_eq++;
}
}
printf("iters=%lu, less=%u, eq=%u, more=%u\n", iter_counter, cnt_less, cnt_eq, cnt_more);
return NULL;
}
void *writer(void *p) {
printf("writer started\n");
uint counter = 0;
while(!stop) {
a.store(counter, std::memory_order_seq_cst);
b.store(counter, std::memory_order_seq_cst);
counter++;
}
}
Последовательное последовательное упорядочение памяти подразумевает, что порядок модификации (атомных объектов, манипулируемых последовательностью), наблюдаемый всеми потоками, является согласованным. Программа ведет себя так, как будто все эти операции выполняются с чередованием в одном общем порядке. Рассмотрим следующие случаи:
Писатель читатель == 0 а = 1 б = 1 б == 1
Результат: aa < bb
,
Писатель читатель а = 1 == 1 б == 0 б = 1
Результат: aa > bb
С замком, например mutex
, вы можете убедиться, что операции не чередуются.
Других решений пока нет …