c++ - 获取释放内存顺序与顺序一致性不同的实际例子是什么?

标签 c++ multithreading c++11 atomic memory-model

显然,顺序一致的原子操作在有效的可观察行为方面不同于有效的 C++ 程序中的仅获取-释放操作。定义在 C++ 标准(C++11 起)或 here 中给出。 .

但是,我从未遇到过获取-释放语义不足且需要顺序一致性的算法或数据结构的真实示例。

什么是现实世界算法或数据结构的实际示例,其中需要顺序一致性并且获取-释放内存顺序不够?

注意,即使是std::mutex does not guarantee sequential consistency .

最佳答案

Peterson 的算法是需要顺序一致性的示例。

在互斥之前的日子里,该算法用于为单个线程提供对 protected 区域的访问权限。 该算法仅适用于 2 个线程,每个线程管理一个表示访问 protected 区域的意图的标志。 如果两者都在(大约)同时设置标志,则两者都会后退并重试。 真正的算法更先进,因为它使用“转向”标志来管理公平访问,但为了显示 seq/cst 和 acq/rel 之间的区别,这不是必需的。

下面是 Peterson 算法的一个准备好编译的简化版本,它实际上表明,如果使用比顺序一致性更弱的东西,算法就会被破坏。 有趣的是,这在 X86 上甚至是坏的,因为该平台允许重新排序存储加载。
存储加载重新排序的问题在于,两个线程都可能通过将它们的 me 标志设置为 true 来表达它们访问 protected 区域的意图,同时它们都读取 false 来自 him 标志(因为该值尚未传播到两个线程)并进入保护区。这对于顺序一致性是不可能的。

使用 gcc,我必须使用 -O3 优化进行编译,以使用 clang 触发 assert那是没有必要的。 两种编译器都使用不同的方法来实现顺序一致性。

#include <thread>
#include <atomic>
#include <assert.h>

std::atomic<bool> flag1{false};
std::atomic<bool> flag2{false};

std::atomic<int> counter{0};

// Change these to memory_order_seq_cst to fix the algorithm
static const auto store_ordering = std::memory_order_release;
static const auto load_ordering  = std::memory_order_acquire;

void busy(int n)
{
    auto &me  = (n==1) ? flag1 : flag2;
    auto &him = (n==1) ? flag2 : flag1;

    for (;;)
    {
        for (;;)
        {
            me.store(true, store_ordering);
            if (him.load(load_ordering) == false)
            {
                // got the 'lock'
                break;
            }

            // retention, no wait period -> busy loop
            me.store(false, store_ordering);
        }

        int tmp = counter.fetch_add(1, std::memory_order_relaxed);
        assert(tmp == 0);

        /*
         * critical area
         */

        tmp = counter.fetch_sub(1, std::memory_order_relaxed);
        assert(tmp == 1);

        me.store(false, store_ordering);
    }
}


int main()
{
    std::thread t1{busy, 1};
    std::thread t2{busy, 2};

    t1.join();
    t2.join();
}

关于c++ - 获取释放内存顺序与顺序一致性不同的实际例子是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41858540/

相关文章:

c++ - `*this` 外部成员函数体?

c++ - 模板参数包中的 6 个点是什么?

c++ - C/C++ 内存占用,每个源文件

c - OpenMP 中的插入排序

java Thread#isInterrupt 对于死线程总是返回 false

c++ - 在线程中复制文件以防止卡住应用程序

c++11 - boost::filesystem::current_path() 返回空路径

c++ - 表达式必须有类类型

c++ - 无法解析符号 vector

c++ - "??*"C++转义序列