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 абзацы и строки.