Я пытался найти подробности по этому поводу, я даже читал стандарт на мьютексы и атомики ... но все же я не мог понять гарантии видимости модели памяти C ++ 11. Насколько я понимаю, очень важной особенностью mutex BESIDE взаимного исключения является обеспечение видимости. Также недостаточно того, что только один поток за раз увеличивает счетчик, важно, чтобы поток увеличивал счетчик, который был сохранен потоком, который последним использовал мьютекс (я действительно не знаю, почему люди не упоминают об этом больше при обсуждении мьютексы, может у меня были плохие учителя :)). Итак, из того, что я могу сказать, atomic не обеспечивает немедленную видимость: (от человека, который поддерживает boost :: thread и реализовал поток C ++ 11 и библиотеку мьютексов):
Забор с memory_order_seq_cst не обеспечивает немедленную видимость для других потоков (как и инструкция MFENCE). Ограничения порядка памяти C ++ 0x - это всего лишь ограничения порядка. Операции memory_order_seq_cst образуют общий порядок, но нет никаких ограничений на то, что это за порядок, за исключением того, что он должен быть согласован всеми потоками, и он не должен нарушать другие ограничения порядка. В частности, потоки могут продолжать видеть «устаревшие» значения в течение некоторого времени при условии, что они видят значения в порядке, соответствующем ограничениям.
И меня это устраивает. Но проблема в том, что мне трудно понять, какие конструкции C ++ 11, касающиеся атомарных, являются «глобальными» и которые обеспечивают согласованность только атомарных переменных. В частности, у меня есть понимание, какой (если таковой имеется) из следующих порядков памяти гарантирует, что до и после загрузки и сохранения будет стоять ограждение памяти: http://www.stdthread.co.uk/doc/headers/atomic/memory_order.html
Из того, что я могу сказать, std :: memory_order_seq_cst вставляет барьер памяти, в то время как другие только обеспечивают упорядочение операций в определенной области памяти.
Так может кто-нибудь прояснить это, я предполагаю, что многие люди будут делать ужасные ошибки, используя std :: atomic, особенно, если они не используют default (std :: memory_order_seq_cst memory ordering)
2. Если я прав, делает это означает, что вторая строка в этом коде избыточна:
atomicVar.store(42);
std::atomic_thread_fence(std::memory_order_seq_cst);
3. предъявляют ли std :: atomic_thread_fences те же требования, что и мьютексы, в том смысле, что для обеспечения согласованности последовательностей на неатомарных варах необходимо выполнять std :: atomic_thread_fence (std :: memory_order_seq_cst); перед загрузкой и std :: atomic_thread_fence (std :: memory_order_seq_cst);
после сохранения?
4. Является ли
{
regularSum+=atomicVar.load();
regularVar1++;
regularVar2++;
}
//...
{
regularVar1++;
regularVar2++;
atomicVar.store(74656);
}
эквивалентно
std::mutex mtx;
{
std::unique_lock<std::mutex> ul(mtx);
sum+=nowRegularVar;
regularVar++;
regularVar2++;
}
//..
{
std::unique_lock<std::mutex> ul(mtx);
regularVar1++;
regularVar2++;
nowRegularVar=(74656);
}
Думаю, что нет, но хотелось бы убедиться.
РЕДАКТИРОВАТЬ: 5. Можно утверждать огонь?
Существует только два потока.
atomic<int*> p=nullptr;
первый поток пишет
{
nonatomic_p=(int*) malloc(16*1024*sizeof(int));
for(int i=0;i<16*1024;++i)
nonatomic_p[i]=42;
p=nonatomic;
}
вторая ветка читает
{
while (p==nullptr)
{
}
assert(p[1234]==42);//1234-random idx in array
}