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

标签 c++ multithreading pointers atomic

在下面的代码中,线程 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

但是在下面的代码中,线程2中的*x会不会一直是10呢?

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 对其他线程也是可见的,栅栏是不必要的。 IE。 b.store(true, std::memory_order_release) 就足够了。消费者代码需要执行 b.load(std::memory_order_acquire)

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

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

关于c++ - 从 C++ 中的另一个线程读取指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42414940/

相关文章:

c++ - 多线程 Libcurl

c++ - 在 OpenGL 中使用 Qt 拾色

c++ - 如何在指针数组中插入一个对象

java - MVC 进度条线程

c# - 在不同的虚拟机上发送 C# worker

c - 如何在C中访问char指针数组

c++ - 在 C++ 继承中,当指向基类的指针对象指向派生类时,不调用派生类析构函数

multithreading - WinRT 是否仍然具有相同的旧 UI 线程限制?

c - 链接列表,在函数中将列表头作为参数传递时不起作用

c - C 中仅使用指针的二叉树