В какой степени атомарные типы должны использоваться для обеспечения видимости перекрестных потоков?


Задается такая структура:

struct foo {
    atomic_int refcount; /* atomic access */
    char* bar1;          /* read-only */
    char* bar2;          /* read-only */
};

Строго говоря: необходимо ли использовать atomic_intptr_t для bar1 и bar2, чтобы гарантировать сквозную видимость неатомных переменных, при условии, что я использую правильную семантику приобретения/освобождения?

2 3

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.

(на самом деле я разместил комментарий на этот счет в атомной беседе Херба Саттера.)