Как libcxx std :: counting_semaphore реализует «Сильно бывает раньше» для выпуска / приобретения? - PullRequest
6 голосов
/ 02 августа 2020

libc ++ std::counting_semaphore использует atomi c приращение с memory_order_release в release метод :

    void release(ptrdiff_t __update = 1)
    {
        if(0 < __a.fetch_add(__update, memory_order_release))
            ;
        else if(__update > 1)
            __a.notify_all();
        else
            __a.notify_one();
    }

И сравните обмен с memory_order_acquire успешным порядком памяти в acquire метод :

    void acquire()
    {
        auto const __test_fn = [=]() -> bool {
            auto __old = __a.load(memory_order_relaxed);
            return (__old != 0) && __a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
        };
        __cxx_atomic_wait(&__a.__a_, __test_fn);
    }

Очевидный выбор синхронизировать сбор данных с выпуском.

Однако черновик C ++ 20 говорит :

void release(ptrdiff_t update = 1);

...

Синхронизация: Сильно происходит раньше вызовы try_acquire, которые наблюдают за результатом эффектов.

Сильно происходит до того, как немного больше, чем синхронизируется с , черновик C ++ 20 говорит: :

Оценка A строго происходит перед оценкой D, если

  • (12.1) A находится в последовательности перед D, или
  • (12.2) A синхронизируется с D, и оба A и D являются последовательно согласованными операциями atomi c ([atomics.order]), или
  • (12.3) существуют оценки B и C такие, что A упорядочивается до B, B просто происходит до C, а C упорядочивается до D, или
  • (12.4) есть оценка B, такая, что A строго происходит до B, а B строго происходит до D.

Думаю, здесь лучше всего подошел бы 12.2, где A - fetch_add, D - compare_exchange_strong. Но помимо синхронизации с, они должны были быть seq_cst!

Попытка 12.3, похоже, тоже не помогает. Мы звоним по fetch_add B и compare_exchange_strong C. Хорошо, но где же тогда A и D?

Итак, как это работает (согласно проекту стандарта C ++ 20)?

То же самое относится к std::latch и std::barrier.

Я выбрал один (std::semaphore), чтобы легко указать c абзацы и строки.

...