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

硬件已实现缓存一致性(如MESI),为何仍会出现竞态条件?

问题分析与解答

问题代码

#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <mutex>

using namespace std::chrono;

const int nthreads = 4;
const int64_t ndata = 1600000;

int total_sum = 0;

void compute_sum(int tid, std::vector<int>& d)
{
  int st = (ndata / nthreads) * tid;
  int en = (ndata / nthreads) * (tid + 1);
  for (int i = st; i < en; i++) {
    total_sum += d[i];
  }
}

int main(int argc, char ** arg)
{
  std::vector<std::thread> threads;
  
  std::vector<int> data;
  for (int i = 0; i < ndata; i++) {
    data.push_back(i);
  }

  for (int i = 0; i < nthreads; i++) {
    threads.push_back(std::thread(compute_sum, i, std::ref(data)));
  }
  
  for (auto &th : threads) {
    th.join();
  }
  return 0;
}

为什么MESI协议无法避免竞态条件?

MESI这类缓存一致性协议解决的是缓存间的数据可见性问题:它保证当一个CPU核心修改了缓存中的共享数据后,其他核心的缓存会同步更新该数据,确保所有核心看到的共享数据是一致的。但它管不了指令执行的原子性——这才是竞态条件的根源。

看代码里的total_sum += d[i],这个操作拆解成CPU指令是三步独立操作:

  1. 从缓存/内存读取total_sum的值到寄存器
  2. 把寄存器里的值加上d[i]
  3. 把新值写回缓存/内存

这三步之间存在执行空隙,很容易被其他线程的指令插入。比如:线程A读取total_sum=10后,还没完成加值和写回,线程B也读取了total_sum=10;接着线程A完成加5操作,写回total_sum=15;最后线程B完成加3操作,写回total_sum=13——直接覆盖了线程A的修改,最终结果少加了5。

MESI只能保证:如果线程B是在线程A写回之后读取total_sum,那它拿到的是最新的15;但如果线程B是在A写回之前读的,它拿到的还是旧值,MESI无法阻止这种“指令交错执行”的情况。要解决竞态条件,必须用原子操作(比如std::atomic<int>)把这三步打包成一个不可分割的原子指令,或者用锁保证同一时间只有一个线程执行该操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 04:57:06