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

单读写者seq_lock实现中,如何用memcpy保证内存一致性?

单读写者场景下SeqLock的内存序问题与修复方案

原代码实现

#include <atomic>
#include <string.h>

std::atomic<std::size_t> seq_;
std::size_t push_seq = 0;
char value_[32];
char load_copy[32];
char store_copy[32];

void load() {
  std::size_t seq0, seq1;
  do {
    seq0 = seq_.load(std::memory_order_acquire);
    memcpy(load_copy, value_, 32);
    seq1 = seq_.load(std::memory_order_relaxed);
  } while (seq0 != seq1 || seq0 & 1);
}

void store() {
  seq_.store(++push_seq, std::memory_order_relaxed);
  memcpy(value_, store_copy, 32);
  seq_.store(++push_seq, std::memory_order_release);
}

存在的问题

  • store()函数:第一个seq_.store使用memory_order_relaxed,无内存约束,编译器/CPU可能将memcpy的写操作重排序到该store之前,导致写者未标记"开始写入"就修改数据,读者可能读到半写的脏数据。
  • load()函数:你担心的"memcpy在acquire load完成前执行"是误解——memory_order_acquire的load语义本身就会阻止后续内存操作(包括memcpy的读)重排序到该load之前,原逻辑这部分是安全的。

尝试的栅栏方案

void load() {
  std::size_t seq0, seq1;
  do {
    seq0 = seq_.load(std::memory_order_acquire);
    memcpy(load_copy, value_, 32);
    std::atomic_thread_fence(std::memory_order_release);
    seq1 = seq_.load(std::memory_order_relaxed);
  } while (seq0 != seq1 || seq0 & 1);
}

void store() {
  seq_.store(++push_seq, std::memory_order_relaxed);
  std::atomic_thread_fence(std::memory_order_acquire);
  memcpy(value_, store_copy, 32);
  seq_.store(++push_seq, std::memory_order_release);
}

方案分析与修复

尝试方案的问题

  • store()中的acquire栅栏:确实能阻止memcpy重排到第一个store之前,这部分有效,但load()中的release栅栏完全冗余——它既不能约束读顺序,也没有同步作用,反而浪费性能。

可行的修复方案

方案1:保留有效栅栏,移除冗余部分

只保留store()中的acquire栅栏,移除load()的多余栅栏,即可解决问题:

void load() {
  std::size_t seq0, seq1;
  do {
    seq0 = seq_.load(std::memory_order_acquire);
    memcpy(load_copy, value_, 32);
    seq1 = seq_.load(std::memory_order_relaxed);
  } while (seq0 != seq1 || seq0 & 1);
}

void store() {
  seq_.store(++push_seq, std::memory_order_relaxed);
  std::atomic_thread_fence(std::memory_order_acquire); // 确保store先于memcpy执行
  memcpy(value_, store_copy, 32);
  seq_.store(++push_seq, std::memory_order_release);
}

方案2:调整store()的内存序,无需栅栏

将第一个seq_.store的内存序改为memory_order_seq_cst,利用全局顺序约束阻止重排:

void store() {
  seq_.store(++push_seq, std::memory_order_seq_cst); // 全局顺序保证先标记写开始
  memcpy(value_, store_copy, 32);
  seq_.store(++push_seq, std::memory_order_release);
}

方案3:标准SeqLock内存序写法

写者用双重release,读者用双重acquire,贴合SeqLock标准语义,单读写者场景下安全可靠:

void load() {
  std::size_t seq0, seq1;
  do {
    seq0 = seq_.load(std::memory_order_acquire);
    memcpy(load_copy, value_, 32);
    seq1 = seq_.load(std::memory_order_acquire);
  } while (seq0 != seq1 || seq0 & 1);
}

void store() {
  seq_.store(++push_seq, std::memory_order_release);
  memcpy(value_, store_copy, 32);
  seq_.store(++push_seq, std::memory_order_release);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:21:02