C&C++   发布时间:2022-04-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了c – 了解内存序列和std :: memory_order_relaxed大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在研究C内存序列,但它非常令人困惑.

例如:

void sumUp(std::atomic<int>& sum,std::vector<int>& val)
{
   int tmpSum = 0;
   for(auto i = 0; i < 100; ++i) tmpSum += val[i];

   sum.fetch_add(tmpSum,std::memory_order_relaxed);
}

我不明白sum.fetch_add()在tmpSum = val [i]之后运行.
由于它不是有序的,sum.fetch_add()可以在tmpSum = val [i]之前运行吗?

总和0可能吗?

非常感谢.

解决方法

memory_order在单个线程的上下文中没有可观察到的效果

让我们看看(x,a和b最初为0):

auto t1(std::atomic<int>& x,int& a,int& b)
{
    a = 3;                                       // 1
    b = 5;                                       // 2
    x.store(a,std::memory_order_relaxed);       // 3
}

因为(1)和(2)不依赖于另一个,所以编译器可以重新排序它们.例如.可以做(1) – > (2)或(2) – > (1)

因为(3)依赖于(1)((1)写入a和(3)从a读取)编译器在(1)之前不能做(3).这与(3)中指定的内存顺序无关

因为(3)不依赖于(2),通常在单线程模型中,编译器可以在(2)之前做(3).

但由于x是原子的,虑另一个线程这样做(x,a和b是对提供给t1的相同参数的引用,并且最初都是0):

auto t2(std::atomic<int>& x,int& b)
{
    while(x.load(std::memory_order_relaxed) == 3)  // 4
        assert(b == 5);                            // 5
}

该线程等待直到x为3,然后断言b为5.现在您可以看到顺序单线程世界(2)和(3)如何在没有任何可观察行为的情况下重新排序,但在多线程模型中,顺序(2)和(3)可能会对程序的行为产生影响.

这就是memory_order的作用:它指定在原子之前或之后可以对单个线程产生任何影响的操作是否可以重新排序.原因是它们可能对多线程程序产生影响.编译器不能知道这个,只有程序员,因此额外的memory_order参数.

对于memory_order_relaxed,断言可能会失败,因为(2)可能发生在(3)之后,但是对于memory_order_seq_cst(认),断言将永远不会失败,因为(2)发生在(3)之前.

回到你的例子,无论你指定什么memory_order,都保证tmpSum = val [i];会在sum.fetch_add(tmpSum,std :: memory_order_relaxed)之前发生;因为第二个取决于第一个. memory_order会影响可能重新排序不影响原子操作的指令.例如.如果你有一个无关的int = 24.

便说一句,官方术语是“先前排序”和“后排序”

在现实世界中,硬件使事情变得复杂一些.操作可以在当前线程中以一个顺序出现,但另一个线程可以以另一个顺序看到它们,因此更严格的memory_orders必须采用额外的措施来确保跨线程的顺序一致.

严格来说,在此示例中,如果使用memory_order_relaxed,我们将具有未定义的行为,因为对b的访问不会跨线程同步.

大佬总结

以上是大佬教程为你收集整理的c – 了解内存序列和std :: memory_order_relaxed全部内容,希望文章能够帮你解决c – 了解内存序列和std :: memory_order_relaxed所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。