libcxx std::counting_semaphore 如何为发布/获取实现“强烈发生在之前”?

Ale*_*iev 8 c++ memory-barriers language-lawyer stdatomic c++20

libc++在方法中std::counting_semaphore使用原子增量:memory_order_releaserelease

    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();
    }
Run Code Online (Sandbox Code Playgroud)

memory_order_acquireacquire方法中将交换与成功的内存顺序进行比较:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

使获取与发布同步的明显选择。


但是,C++20 草案

void release(ptrdiff_t update = 1);
Run Code Online (Sandbox Code Playgroud)

...

同步:强烈发生在调用 try_acquire 之前,观察效果的结果。

强发生在同步之前有点多,C++20 草案

评估 A 强烈发生在评估 D 之前,如果,

  • (12.1) A 在 D 之前被排序,或
  • (12.2) A 与 D 同步,并且 A 和 D 都是顺序一致的原子操作([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_addB 和compare_exchange_strongC。很好,但是 A 和 D 在哪里?

那么它是如何工作的(根据 C++20 标准草案)?


这同样适用于std::latchstd::barrier

我选择了一个 ( std::semaphore) 来轻松引用特定的段落和行。