C++ 并发编程指南(11)原子操作 | 11.7、使用栅栏实现同步


前言

C++多线程中的atomic_thread_fence是一种同步原语,用于确保在多线程环境下,内存操作的顺序得到保证。它是C++11标准中引入的,主要用于解决多线程中的内存可见性和重排序问题。

一、栅栏

1、栅栏的作用

在多线程编程中,由于编译器和处理器的优化,指令的执行顺序可能与代码编写顺序不一致。这可能导致一些意料之外的结果。为了解决这个问题,可以使用atomic_thread_fence来限制指令的执行顺序,确保线程之间的操作按照预期的顺序执行。下面看下之前的一个示例:

std::atomic<bool> x, y;
std::atomic<int> z;

void write_x_then_y() {
    x.store(true, std::memory_order_relaxed);  // 1
    y.store(true, std::memory_order_relaxed);  // 2
}

void read_y_then_x() {
    while (!y.load(std::memory_order_relaxed)) { // 3
        std::cout << "y load false" << std::endl;
    }

    if (x.load(std::memory_order_relaxed)) { //4
        ++z;
    }
}

void TestOrderRelaxed() {
    std::thread t1(write_x_then_y);
    std::thread t2(read_y_then_x);
    t1.join();
    t2.join();
    assert(z.load() != 0); // 5
}

这个示例之前有介绍过,当使用std::memory_order_relaxed内存序时,断言有可能被触发,使用Acquire Release Ordering顺序模型可以解决该问题,也可以考虑通过栅栏机制解决该问题。

2、使用栅栏

std::atomic_thread_fence函数接受一个std::memory_order枚举值作为参数,如下:

  • memory_order_acquire:在这个屏障之前的读/写指令不会排到其后。
  • memory_order_release:在这个屏障之后的读/写指令不会排到其前。
  • memory_order_acq_rel:结合了memory_order_acquirememory_order_release的功能。
  • memory_order_seq_cst:最强的顺序约束,等同于单线程程序中的顺序。

下面通过栅栏机制解决前面的问题,如下:

void write_x_then_y_fence()
{
    x.store(true, std::memory_order_relaxed);  //1
    std::atomic_thread_fence(std::memory_order_release);  //2
    y.store(true, std::memory_order_relaxed);  //3
}

void read_y_then_x_fence()
{
    while (!y.load(std::memory_order_relaxed));  //4
    std::atomic_thread_fence(std::memory_order_acquire); //5
    if (x.load(std::memory_order_relaxed))  //6
        ++z;
}

3、注意事项

  • 过度使用std::atomic_thread_fence可能会降低性能,因为它会阻止编译器和处理器进行某些优化。
  • 在选择std::memory_order参数时,应确保理解其含义和潜在的影响。错误的内存序选择可能会导致数据竞争或其他并发问题。
  • 在编写多线程代码时,应始终使用原子操作或其他同步机制来保护共享数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值