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

多线程写入内存映射文件:刷盘与解映射前需同步吗?

问题解答

1. 是否需要同步写入线程与刷盘线程?

是的,你需要正确的内存同步机制,仅用relaxed原子操作和编译器屏障不足以保证正确性:

  • 写入线程:NUM_WRITERS.fetch_sub(1)必须使用memory_order_release而非relaxed。release语义会确保memcpy的所有写入操作,在NUM_WRITERS的递减操作对其他线程可见前就已完成,且对后续同步操作可见(包括CPU缓存层面的同步)。单纯的编译器屏障只能阻止编译器指令重排,无法约束CPU的指令重排行为。
  • 刷盘等待线程:循环中加载NUM_WRITERS时必须使用memory_order_acquire而非relaxed。acquire语义会确保执行flush_async和unmap前,所有写入线程通过release语义发布的写入操作都已被当前线程可见。

2. CPU和操作系统是否保证缓存写入最终到磁盘?

  • CPU的缓存一致性机制仅保证线程间的缓存数据同步,但不会自动将缓存数据刷写到磁盘。操作系统虽会定期异步刷新页缓存到磁盘,但这个过程是不确定的,无法依赖它来保证数据及时持久化。
  • 你必须显式调用msync(Linux)或FlushViewOfFile(Windows)来强制数据从主内存写入磁盘。在此之前,需要通过内存屏障确保所有写入线程的数据已从CPU缓存同步到主内存(或至少对操作系统的刷盘操作可见)。

3. 能否仅使用relaxed原子操作追踪数据?

  • CURRENT_OFFSET使用relaxed是安全的:因为每个线程的写入区域不重叠,原子操作的原子性(与内存顺序无关)已能保证每个线程获得唯一偏移量,不会出现冲突。
  • 但NUM_WRITERS的操作不能全用relaxed:如前所述,必须通过release/acquire语义建立写入操作与刷盘操作之间的happens-before关系,确保刷盘时所有写入都已完成且可见。

修正后的伪代码

static AtomicUint NUM_WRITERS = 0;
static AtomicUint CURRENT_OFFSET = 0;

void some_thread_fn(void* buffer, const uint8_t* payload, size_t payload_size, size_t buffer_size) {
    NUM_WRITERS.fetch_add(1, memory_order_relaxed);
    size_t offset = CURRENT_OFFSET.fetch_add(payload_size, memory_order_relaxed);
    void* dst = (uint8_t*)buffer + offset;
    memcpy(dst, payload, payload_size);
    
    // 使用release语义确保memcpy写入在NUM_WRITERS递减前完成
    NUM_WRITERS.fetch_sub(1, memory_order_release);

    if (offset + payload_size < buffer_size) {
        // 由其他线程负责解映射
        return;
    }

    // 使用acquire语义等待所有写入完成,并确保所有写入可见
    while (NUM_WRITERS.load(memory_order_acquire) > 0) {
        _mm_pause();
    }

    flush_async(buffer);
    unmap(buffer);
}

关键修正点:

  1. 将NUM_WRITERS.fetch_sub(1)的内存顺序改为memory_order_release
  2. 将循环中NUM_WRITERS.load()的内存顺序改为memory_order_acquire
  3. 移除不必要的编译器屏障,因为原子操作的memory_order已包含编译器和CPU的重排约束

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:23:41