В какой степени атомарные типы должны использоваться для обеспечения видимости перекрестных потоков?
Задается такая структура:
struct foo {
atomic_int refcount; /* atomic access */
char* bar1; /* read-only */
char* bar2; /* read-only */
};
Строго говоря: необходимо ли использовать atomic_intptr_t
для bar1
и bar2
, чтобы гарантировать сквозную видимость неатомных переменных, при условии, что я использую правильную семантику приобретения/освобождения?
2 ответа:
Взятые абстрактно, любые операции памяти, которые происходят между операциями получения/освобождения атомарной переменной, будут вести себя так, как если бы вы приобрели и выпустили абстрактный тип мьютекса (POSIX, WinAPI и т. д.), поскольку именно так они обычно реализуются в любом случае. Основная цель атомарных операций и определенной модели памяти-определить, как неатомные обращения к памяти упорядочиваются вокруг атомарных обращений. Поэтому они не должны быть атомарными.
Если вы никогда не пишете в указатели, тогда вам понадобится только барьер памяти после инициализации структуры, чтобы гарантировать, что начальные значения станут видимыми в других потоках. Если в вашем критическом разделе вы изменяете то, на что ссылаются указатели, семантика приобретения/выпуска гарантирует, что эти изменения также станут видимыми.
Полезное чтение (я не уверен в каких-либо различиях между памятью C11 и C++11 модель): http://en.cppreference.com/w/cpp/atomic/memory_order
Http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
Редактирования: добавил ссылку.
Чтобы быть педантичным (что хорошо, когда речь идет о моделях памяти), нет ничего, что требует, чтобы изменениякогда-либо становились видимыми для других потоков. Все, что вам гарантировано, - это то, что происходит в точке синхронизации: Если ваше приобретение read считывает определенное новое значение, тогда вам гарантировано, что все эффекты потока, который использовал release-write для записи этого нового значения, которое появилось до записи в этом потоке, произошли и видны. Но на самом деле у вас нет гарантии , что ваше приобретение-чтение когда-либо прочитает новое значение.
C++11 немного более конкретен в этом отношении и содержит "примечание", что "операция станет видимой для всех других потоков в течение конечного периода времени" (C++11, 1.10/25), но я не вижу никакого аналогичного утверждения в C11.
(на самом деле я разместил комментарий на этот счет в атомной беседе Херба Саттера.)