You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多存储操作内存序问题:生产者-消费者同步代码的正确性与修复

问题分析与修复

问题本质

你担心的操作重排风险确实存在,且会直接导致断言失败。因为所有原子操作都使用了memory_order_relaxed,这种内存序不保证任何跨线程的操作顺序可见性——编译器、CPU完全可以把生产者里的barrier[0].store/barrier[1].store重排到runcnt.store(2)之前执行。

一旦出现这种重排,某个消费者线程会先看到自己的barrier被设为1,随后执行runcnt.fetch_sub(1),但此时生产者还未将runcnt设为2,prev的值就是初始的0,直接触发assert(prev > 0)失败。

修复方案

核心是要在生产者的runcnt.store(2)和两个barrier.store之间建立**先行发生(happens-before)**关系,确保消费者看到barrier的修改时,一定能看到runcnt已经被设为2。

方案1:用Release-Acquire内存序配对

修改生产者的runcnt.store为memory_order_release,消费者的barrier[index].exchange为memory_order_acquire:

extern atomic<int> barrier[2];
atomic_int runcnt{0};

void producer() {
    // 用release确保后续的barrier store一定在这个操作之后可见
    runcnt.store(2, memory_order_release);
    barrier[0].store(1, memory_order_relaxed);
    barrier[1].store(1, memory_order_relaxed);
    
    while (runcnt.load(memory_order_relaxed)) {
        cpu_pause();
    }
}

void consumer(unsigned index) {
   while (true) {
    // 用acquire确保看到barrier的修改时,生产者的runcnt.store已经可见
    if (barrier[index].exchange(false, memory_order_acquire)) {
      int prev = runcnt.fetch_sub(1, memory_order_relaxed);
      assert(prev > 0);
    }
   }
}

方案2:显式插入内存栅栏

如果不想修改太多内存序,可以在生产者的runcnt.store之后插入release栅栏,消费者的exchange用acquire:

extern atomic<int> barrier[2];
atomic_int runcnt{0};

void producer() {
    runcnt.store(2, memory_order_relaxed);
    // 栅栏确保之前的store操作一定在之后的store之前被其他线程看到
    std::atomic_thread_fence(std::memory_order_release);
    barrier[0].store(1, memory_order_relaxed);
    barrier[1].store(1, memory_order_relaxed);
    
    while (runcnt.load(memory_order_relaxed)) {
        cpu_pause();
    }
}

void consumer(unsigned index) {
   while (true) {
    if (barrier[index].exchange(false, memory_order_acquire)) {
      int prev = runcnt.fetch_sub(1, memory_order_relaxed);
      assert(prev > 0);
    }
   }
}

两种方案都能保证:消费者看到barrier被设置时,runcnt的值已经是2,fetch_sub得到的prev必然大于0,断言不会触发。

内容的提问来源于stack exchange,提问作者Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:28:21