从C++中的另一个线程读取指针

Reading pointers from another thread in C++

本文关键字:线程 读取 指针 另一个 C++      更新时间:2023-10-16

在下面的代码中,线程 2 中x的值将始终为 10,因为原子线程围栏。

int x;
atomic<bool> b(false);
// thread 1:
x = 10;
atomic_thread_fence(memory_order_release);
b = true;
// thread 2:
while(!b){}
atomic_thread_fence(memory_order_acquire);
assert(x == 10); // x will always be 10

但是在下面的代码中,线程 10 中的*x2 将始终为 2 吗?

int* x = new int;
atomic<bool> b(false);
// thread 1:
*x = 10;
atomic_thread_fence(memory_order_release);
b = true;
// thread 2:
while(!b){}
atomic_thread_fence(memory_order_acquire);
assert(*x == 10); // will *x always be 10?

在这两种情况下,您都会得到10,无论商店是直接完成还是通过指针完成,这里都没有区别。

这里不需要内存围栏,因为b = true本质上是b.store(true, std::memory_order_seq_cst)的 - 带有围栏的获取发布。

此类内存顺序可防止编译器围绕操作对存储和加载进行重新排序,并使前面的存储在此存储变得可见时对其他线程可见。

如果比较这两个函数的生成代码:

#include <atomic>
int x;
std::atomic<bool> b(false);
void f() {
x = 10;
std::atomic_thread_fence(std::memory_order_release);
b = true;
}
void g() {
x = 10;
b = true;
}

它是相同的:

f():
movl    $10, x(%rip)
movb    $1, b(%rip)
mfence
ret
g():
movl    $10, x(%rip)
movb    $1, b(%rip)
mfence
ret

不过,在您的特定情况下,在我看来,您只需要std::memory_order_release商店即可b使商店x对其他线程也可见,围栏是不必要的。 即b.store(true, std::memory_order_release)在这里就足够了。消费者代码需要做b.load(std::memory_order_acquire)

标准互斥锁确实在锁定时获取内存顺序,在解锁时释放内存顺序(这是术语获取/释放的来源),不涉及围栏。

很少需要显式围栏,主要是在硬件驱动程序中。在用户空间模式下,由于对 C++11 内存模型的误解,通常会放置代码围栏。围栏是最昂贵的原子同步机制,这是避免它们的主要原因。