根据Jeff Preshing博客中的an article:
释放栅栏防止按程序顺序在它之前的任何读或写与按程序顺序在它之后的任何写的存储器重新排序。
他还有一个很棒的帖子,解释了释放围栏和释放操作here之间的区别。
尽管这些博客文章中有明确的解释,但我仍然不明白如何从内存操作重新排序与提供释放围栏保证的潜在围栏机制的Angular 来解释std::atomic_thread_fence(std:memory_order_release);
这样的释放围栏调用。
是不是编译器必须保证在编译到机器码时避免在fence语句调用之前的线程中出现后面的写调用的可能性,并且CPU在处理它时必须保证相同?
换句话说,到底什么时候栅栏电话从一个声明变成了一个保证?
最重要的是,编译器或CPU重新排序是否有可能重新排序在fence语句的程序顺序之后的写操作,使其在该过程的执行时位于fence之前?
1条答案
按热度按时间oknrviil1#
是不是编译器必须保证在编译到机器码时避免在fence语句调用之前的线程中出现后面的写调用的可能性,并且CPU在处理它时必须保证相同?
某些编译器优化必须被禁用。编译器必须发出阻止某些CPU优化的代码,包括必要的CPU围栏指令。这就是保证...
编译器或CPU重新排序是否有可能重新排序继fence语句的程序顺序之后的写操作,使其在该进程的执行时间先于fence?
带有
std::memory_order_release
的std::atomic_thread_fence
可防止围栏之前(程序顺序中的"之前")的加载和存储与围栏之后的任何存储重新排序(后续加载可在之前重新排序)。在执行时,只要保证成立,可能不需要实际的存储器屏障指令本身。具有
std::memory_order_acquire
的std::atomic_thread_fence
防止围栏之后(在程序顺序中为"之后")的加载和存储与围栏之前的任何加载重新排序(较早的存储可以在之后重新排序)。在执行时,可能不需要实际的存储器屏障指令本身,只要保证成立。注意,这分别比std::atomic::store和std::atomic::load更严格。
std::atomic<T>::store
与std::memory_order_release
一起使用可以防止之前的加载和存储仅使用该特定存储重新排序。后续的加载和存储可以在之前重新排序。理论上,这是一个传统的单向释放。(实际上,可能会使用比严格需要的更严格的同步。)std::atomic<T>::load
与std::memory_order_acquire
一起使用可以防止仅使用该特定加载对之后的加载和存储进行重新排序。较早的加载和存储可以在之后重新排序。理论上,这是传统的单向获取。