理解memory_order_relaxed [英] Understanding memory_order_relaxed

查看:1023
本文介绍了理解memory_order_relaxed的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解memory_order_relaxed的细节。我指的是以下链接: CPP参考

  #include< future> 
#include< atomic>

std :: atomic< int *> ptr {nullptr};

void fun1(){
ptr.store(new int {0},std :: memory_order_relaxed);
}

void fun2(){
while(!ptr.load(std :: memory_order_relaxed));
}

int main(){
std :: async(std :: launch :: async,fun1);
std :: async(std :: launch :: async,fun2);问题1:在上面的代码中,在技术上可能fun2是可能的在无限循环中,它看到ptr的值为nullptr,即使设置ptr的线程已经完成运行?



如果假设,我将上述代码更改为以下代码:

  #include< future> 
#include< atomic>

std :: atomic< int> i {0};
std :: atomic< int *> ptr {nullptr};

void fun1(){
i.store(1,std :: memory_order_relaxed);
i.store(2,std :: memory_order_relaxed);
ptr.store(new int {0},std :: memory_order_release);

}

void fun2(){
while(!ptr.load(std :: memory_order_acquire));
int x = i.load(std :: memory_order_relaxed);
}

int main(){
std :: async(std :: launch :: async,fun1);
std :: async(std :: launch :: async,fun2);
}

相关问题:在fun2上面的代码中,的原子i作为1或者它放心会看到值2?

解决方案

一个有趣的观察是,代码,没有实际的并发;即 fun1 fun2 顺序运行,原因是在特定条件下(包括调用使用 std :: launch :: async 启动策略), std :: future 由 std :: async 返回的code>对象具有析构函数块,直到启动的函数调用返回。由于忽略了返回对象,它的析构函数在语句结束之前被调用。如果你在 main()(即在之前启动 fun2 code>),你的程序将被捕获在一个无限循环中,因为 fun1 永远不会运行。



std :: future 销毁等待行为有些争议(甚至在标准委员会中)因为我假设你不是这个意思,我将自由重写 main 中的两个语句(两个示例)为:

  auto tmp1 = std :: async(std :: launch :: async,fun1); 
auto tmp2 = std :: async(std :: launch :: async,fun2);

这将延迟实际的 std :: future 返回对象破坏直到 main 结束,使 fun1 fun2 以异步方式运行。


在技术上可能fun2处于无限循环中,它看到ptr的值为nullptr,即使设置ptr已完成运行?


否,这不可能与 std :: atomic (在一个真实的平台上,如评论部分所述)。使用非 - std :: atomic 变量,编译器可以(理论上)选择仅将值保存在寄存器中,但是 std :: atomic 被存储,并且高速缓存一致性将该值传播到其他线程。使用 std :: memory_order_relaxed 在这里很好,只要你不解引用指针。


在上面的代码中,fun2是否可以看到atom i的值为1或者是否可以看到值2?


保证在变量 x 中看到值2。

fun1 将两个不同的值存储到同一个变量,但由于存在明确的依赖关系,因此这些不会重新排序。



fun1 中, ptr.store code> std :: memory_order_release 使用阻止 i.store(2) std :: memory_order_relaxed 从下移到其发布屏障。在 fun2 中, ptr.load std :: memory_order_acquire 阻止 i.load std :: memory_order_relaxed 跨越其获取障碍。这保证 fun2 中的 x 将具有值2.



请注意,通过在所有原子上使用 std :: memory_order_relaxed ,可以看到 x i 的访问的相对顺序,对于 ptr.store code>和 ptr.load


I am trying to understand the specifics of memory_order_relaxed. I am referring to this link : CPP Reference.

#include <future>
#include <atomic>

std::atomic<int*> ptr {nullptr};

void fun1(){
        ptr.store(new int{0}, std::memory_order_relaxed);
}

void fun2(){
        while(!ptr.load(std::memory_order_relaxed));
}

int main(){
        std::async(std::launch::async, fun1);
        std::async(std::launch::async, fun2);
}

Question 1: In the code above, is it technically possible for fun2 to be in an infinite loop where it sees the value of ptr as nullptr even if the thread that sets ptr has finished running?

If suppose, I change the code above to something like this instead:

#include <future>
#include <atomic>

std::atomic<int> i {0};
std::atomic<int*> ptr {nullptr};

void fun1(){
        i.store(1, std::memory_order_relaxed);
        i.store(2, std::memory_order_relaxed);
        ptr.store(new int{0}, std::memory_order_release);

}

void fun2(){
        while(!ptr.load(std::memory_order_acquire));
        int x = i.load(std::memory_order_relaxed);
}

int main(){
        std::async(std::launch::async, fun1);
        std::async(std::launch::async, fun2);
}

Related Question: Is it possible in the code above for fun2 to see the value of atomic i as 1 or is it assured that it will see the value 2?

解决方案

An interesting observation is that, with your code, there is no actual concurrency; i.e. fun1 and fun2 run sequentially, the reason being that, under specific conditions (including calling std::async with the std::launch::async launch policy), the std::future object returned by std::async has its destructor block until the launched function call returns. Since you disregard the return object, its destructor is called before the end of the statement. Had you reversed the two statements in main() (i.e. launch fun2 before fun1), your program would have been caught in an infinite loop since fun1 would never run.

This std::future wait-upon-destruction behavior is somewhat controversial (even within the standards committee) and since I assume you didn't mean that, I will take the liberty to rewrite the 2 statements in main for (both examples) to:

auto tmp1 = std::async(std::launch::async, fun1);
auto tmp2 = std::async(std::launch::async, fun2);

This will defer the actual std::future return object destruction till the end of main so that fun1 and fun2 get to run asynchronously.

is it technically possible for fun2 to be in an infinite loop where it sees the value of ptr as nullptr even if the thread that sets ptr has finished running?

No, this is not possible with std::atomic (on a real platform, as was mentioned in the comments section). With a non-std::atomic variable, the compiler could (theoretically) have chosen to keep the value in register only, but a std::atomic is stored and cache coherency will propagate the value to other threads. Using std::memory_order_relaxed is fine here as long as you don't dereference the pointer.

Is it possible in the code above for fun2 to see the value of atomic i as 1 or is it assured that it will see the value 2?

It is guaranteed to see value 2 in variable x.
fun1 stores two different values to the same variable, but since there is a clear dependency, these are not reordered.

In fun1, the ptr.store with std::memory_order_release prevents the i.store(2) with std::memory_order_relaxed from moving down below its release barrier. In fun2, the ptr.load with std::memory_order_acquire prevents the i.load with std::memory_order_relaxed from moving up across its acquire barrier. This guarantees that x in fun2 will have value 2.

Note that by using std::memory_order_relaxed on all atomics, it would be possible to see x with value 0, 1 or 2, depending on the relative ordering of access to atomic variable i with regards to ptr.store and ptr.load.

这篇关于理解memory_order_relaxed的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆