Расслабленный атомный счетчик безопасен? - PullRequest
0 голосов
/ 14 сентября 2018

Гарантирует ли следующий код ожидаемое значение счетчика (40 000 000) в соответствии с моделью памяти C ++ 11?( NOT ограничено x86).

#include <atomic>
#include <thread>
using namespace std;

void ThreadProc(atomic<int>& counter)
{
    for (int i = 0; i < 10000000; i++)
        counter.fetch_add(1, memory_order_relaxed);
}

int main()
{
    #define COUNT 4
    atomic<int> counter = { 0 };
    thread threads[COUNT] = {};

    for (size_t i = 0; i < COUNT; i++)
        threads[i] = thread(ThreadProc, ref(counter));

    for (size_t i = 0; i < COUNT; i++)
        threads[i].join();

    printf("Counter: %i", counter.load(memory_order_relaxed));
    return 0;
}

В частности, координаты ослабленной атомики будут такими, что два потока не будут одновременно считывать текущее значение, независимо увеличивать его, и оба записывать свое увеличенноезначение, фактически потеря одной из записей?

Некоторые строки из спецификации указывают, что счетчик должен постоянно равняться 40 000 000 в приведенном выше примере.

[Примечание: операции, определяющие memory_order_relaxed, ослаблены по отношению к упорядочению памяти.Реализации должны по-прежнему гарантировать, что любой данный атомарный доступ к определенному атомарному объекту будет неделим по отношению ко всем другим атомарным доступам к этому объекту.- примечание конца

.

Атомарные операции чтения-изменения-записи должны всегда читать последнее значение (в порядке изменения), записанное в записи, связанной с чтением-изменением-записать операцию.

.

Все модификации конкретного атомного объекта M происходят в некотором определенном общем порядке, называемом порядком модификации M. Если A и Bмодификации атомного объекта M и A происходят до (как определено ниже) B, тогда A предшествует B в порядке модификации M, который определен ниже.

Этот разговор также поддерживает идею о том, чтоприведенный выше код не распространяется на гонки.https://www.youtube.com/watch?v=KeLBd2EJLOU&feature=youtu.be&t=1h9m30s

Мне кажется, что является неделимым порядком атомных операций, но у нас нет никаких гарантий, что это за порядок.Таким образом, все приращения должны происходить «один перед другим» без гонки, которую я описал выше.

Но тогда некоторые вещи потенциально могут указывать в другом направлении:

Реализации должны делать атомарныемагазины, видимые для атомных нагрузок, в течение разумного промежутка времени.

Коллега сообщил мне, что в выступлении Саттера есть известные ошибки.Хотя я до сих пор не нашел никаких источников для этого.

Несколько членов сообщества C ++ умнее, чем я предполагал, что расслабленное атомарное добавление может быть буферизовано так, чтобы последующее расслабленное атомарное добавление могло читать и обрабатыватьустаревшее значение.

1 Ответ

0 голосов
/ 14 сентября 2018

Код в вашем вопросе не содержит гонок; все приращения упорядочены, и результат 40000000 гарантирован.
Ссылки в вашем вопросе содержат все соответствующие цитаты из стандарта.

Часть, в которой говорится, что атомные хранилища должны быть видны в разумные сроки, относится только к отдельным магазинам.
В вашем случае счетчик увеличивается с помощью атомарной операции чтения-изменения-записи, и те гарантированно будут работать с последней в порядке модификации.

Несколько членов сообщества C ++ (...) подразумевают, что расслабленное атомарное добавление может быть буферизовано так, чтобы последующее расслабленное атомарное добавление могло читать и оперировать устаревшим значением.

Это невозможно, если модификации основаны на атомарных операциях чтения-изменения-записи.
Атомные приращения были бы бесполезны, если бы стандарт не гарантировал надежный результат

...