本文介绍了实际的示例中,获取释放存储器的顺序与顺序一致性不同吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很明显,顺序一致的原子操作在有效的可观察行为上与有效C ++程序中的仅获取释放操作不同。定义是在C ++标准(自C ++ 11起)或中给出的。

Clearly, sequential consistent atomic operations differ in their valid observable behavior from acquire-release only operations in a valid C++ program. Definitions are given in the C++ standard (since C++11) or here.

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

However, I have never come across a real-world example of an algorithm or a data structure that where acquire-release semantics is insufficient and sequential consistency is needed.

这是现实算法或数据结构的实用示例,其中需要顺序一致性而无需获取-释放内存顺序足够吗?

What would be an practical example of a real world algorithm or data structure, where sequential consistency is needed and acquire-release memory order is not enough?

请注意,即使。

Note, that even std::mutex does not guarantee sequential consistency.

推荐答案

彼得森的算法是需要顺序一致性的示例。

Peterson's algorithm is an example of something that requires sequential consistency.

在互斥锁发生之前的几天里,算法被用来向保护区提供单线程访问。
算法仅适用于2个线程,每个线程管理一个标志,该标志表示访问保护区的意图。
如果两个都将标记设置在(大约)同一时间,则两个都会退避并重试。
真正的算法更加先进,因为它使用转弯标志来管理公平访问,但是不必显示seq / cst和acq / rel之间的区别。

In the days before mutexes, the algoritm was used to give a single thread access to a protected area.The algoritm only works with 2 threads, each managing a flag that expresses the intention to access the protected area.If both set the flag at (about) the same time, both will backoff and try again.The real algorithm is more advanced since it uses a 'turn' flag to manage fair access, but to show the difference between seq/cst and acq/rel this is not necessary.

下面是Peterson算法的易于编译的简化版本,实际上表明如果使用了比顺序一致性弱的算法,则算法会被破坏。
有趣的是,由于X86平台允许对存储负载进行重新排序,因此即使在X86上,它也被破坏。

存储负载重新排序的问题是两个线程都可能表达了访问受保护对象的意图。通过将其 me 标志设置为 true 来访问区域,而两者都读取 false him 标志中的$ c>(因为该值尚未传播到两个线程)并进入受保护区域。

Below is a ready-to-compile, simplified version of the Peterson algorithm that actually shows that the algoritms is broken if something weaker than sequential consistency is used.Interestingly enough, this is broken even on X86 since that platform allows store-loads to be reordered.
The problem with store-load reordering is that both threads may express their intention to access the protected area by setting their me flag to true, while both are reading false from the him flag (since the value was not propagated yet to both threads) and enter the protected area. This is not possible with sequential consistency.

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

With gcc, I had to compile with -O3 optimizations to have the assert fire, with clang that was not necessary.Both compilers use a different approach to implement sequential consistency.

#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();
}

这篇关于实际的示例中,获取释放存储器的顺序与顺序一致性不同吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 20:59