- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有以下 C++ 2011 代码:
std::atomic<bool> x, y;
std::atomic<int> z;
void f() {
x.store(true, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
y.store(true, std::memory_order_relaxed);
}
void g() {
while (!y.load(std::memory_order_relaxed)) {}
std::atomic_thread_fence(std::memory_order_acquire);
if (x.load(std::memory_order_relaxed)) ++z;
}
int main() {
x = false;
y = false;
z = 0;
std::thread t1(f);
std::thread t2(g);
t1.join();
t2.join();
assert(z.load() !=0);
return 0;
}
在我的计算机体系结构类(class)中,我们被告知此代码中的断言始终为真。但是现在仔细阅读之后,我真的不明白为什么会这样。
据我所知:
如果我的理解是正确的,为什么不能出现下面的一系列 Action 呢?
y.store(true, std::memory_order_relaxed);
被调用我认为这符合“获取”-“发布”规则,但是,例如在这个问题的最佳答案中:Understanding c++11 memory fences这与我的情况非常相似,它暗示我的操作序列中的第 1 步之类的事情不会在“memory_order_release”之前发生,但没有详细说明其背后的原因。
我对此感到非常困惑,如果有人能对此有所了解,我将非常高兴:)
最佳答案
每种情况下具体发生的情况取决于您实际使用的处理器。例如,x86 可能不会断言这一点,因为它是一个缓存一致的架构(你可以有竞争条件,但是一旦一个值从处理器写入缓存/内存,所有其他处理器都会读取该值 -当然,不会阻止另一个处理器在之后立即写入不同的值,等等)。
因此假设它运行在 ARM 或类似的处理器上,但不能保证其本身缓存一致:
因为对x
的写入是在memory_order_release
之前完成的,t2循环不会退出while(y...)
直到x
也是如此。这意味着当 x
稍后被读取时,它保证是一个,所以 z
被更新。我唯一的小问题是关于你是否也不需要 z
的 release
... 如果 main
在不同的平台上运行处理器比 t1
和 t2
,那么 z
可能仍然在 main
中有一个陈旧的值。
当然,如果你有一个多任务操作系统(或者只是中断做足够的事情等),那不能保证发生 - 因为如果运行 t1 的处理器刷新了它的缓存,那么 t2 可能会读取新的值X。
正如我所说,这不会对 x86 处理器(AMD 或 Intel 处理器)产生影响。
因此,一般性地解释屏障指令(也适用于 Intel 和 AMD process0rs):
首先,我们需要明白,虽然指令可以无序地开始和结束,但处理器确实对顺序有一个普遍的“理解”。假设我们有这个“伪机器代码”:
...
mov $5, x
cmp a, b
jnz L1
mov $4, x
L1: ...
处理器可以在完成“jnz L1”之前推测性地执行 mov $4, x
- 因此,为了解决这个问题,处理器必须回滚 mov $4, x
在 jnz L1
被采用的情况下。
同样,如果我们有:
mov $1, x
wmb // "write memory barrier"
mov $1, y
处理器有规则说“在完成之前的所有存储之前,不要执行任何在 wmb 之后发出的存储指令”。这是一个“特殊”指令——它的存在是为了保证内存排序的精确目的。如果它不这样做,那么你的处理器就坏了,而且设计部门的某个人“他的屁股在线”。
同样,“读取内存屏障”是一条指令,由处理器的设计者保证,在我们完成屏障指令之前的挂起读取之前,处理器不会完成另一次读取。
只要我们不是在研究“实验性”处理器或一些无法正常工作的劣质芯片,它就会以这种方式工作。它是该指令定义的一部分。没有这样的保证,就不可能(或者至少极其复杂和“昂贵”)实现(安全的)自旋锁、信号量、互斥量等。
通常还存在“隐式内存障碍”——也就是说,即使没有,也会导致内存障碍的指令。软件中断(“INT X”指令或类似指令)倾向于执行此操作。
关于带有栅栏和获取/释放的 C++ memory_order,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14492292/
这是一个关于 std::memory_order 的问题C++11 中的规则,当涉及到三个线程时。比如说,一个线程 producer 保存一个值并设置一个标志。然后,另一个线程 relay 在设置另一
我有以下 C++ 2011 代码: std::atomic x, y; std::atomic z; void f() { x.store(true, std::memory_order_rel
我读了一章,我不太喜欢它。我仍然不清楚每个内存顺序之间的区别是什么。这是我目前的猜测,在阅读了更简单的 http://en.cppreference.com/w/cpp/atomic/memory_o
据我所知,std::memory_order 枚举提供内存栅栏,但我需要确定每个 std::memory_order 枚举元素提供的栅栏。下面我按照我对每个 std::memory_order 枚举元
#include std::atomic val{1}; const auto my_order = std::memory_order_relaxed; // const lvalue int m
在像 std::atomic::compare_exchange 这样的函数中,有像 std::memory_order_release、std::memory_order_relaxed 这样的运行
作为我之前 question 的跟进, atomic类使用 memory_order 指定大多数操作范围。与栅栏相反,此内存顺序仅影响其操作的原子。据推测,通过使用几个这样的原子,您可以构建一个并发算
您能否给出一个真实世界的例子,其中出于某种原因使用了 std::atomic::compare_exchange 的两个 memory_order 参数版本(因此一个 memory_order 参数版
std::atomic_flag 有 2 个具有这些默认 std::memory_order 的函数: void clear(std::memory_order order = std::memory
std::atomic 函数,例如 store 和 load 采用 std::memory_order 参数。参数可以在运行时确定,就像任何其他函数参数一样。但是,实际值可能会影响编译期间代码的优化。
谁能解释一下 std::memory_order 是什么?用简单的英语,以及如何将它们与 std::atomic<> 一起使用? 我在这里找到了引用资料和几个例子,但根本不明白。 http://en.
根据cppreference,在C++20中有wait , notify_one , notify_all在std::atomic 。看起来他们做 std::atomic可用作futex。 我问为什么
我阅读了很多帖子并观看了几个 Youtube 视频 C++ 原子和内存模型(ConCpp 17、14)。 当我阅读Concurrency In Action一书的第 5.3.3 节,RELAXED O
似乎与成员函数不同,您无法指定要使用的 memory_order,因此可能最终使用了一些“默认”。 最佳答案 根据 C++ 标准 (§29.7/35),使用非原子调用原子类型 A 的 operator
C++ 标准中滥用 std::memory_order::relaxed 的示例之一: std::atomic x{0}; int a[] = {1,2}; std::for_each(std::ex
我是一名优秀的程序员,十分优秀!