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

C++无锁实现Map原子访问与修改的问题求助

问题根源分析

你的代码没有执行到set函数里的打印语句,核心原因是原子共享指针未初始化:

  • Config结构体中的g_config是std::atomic<std::shared_ptr<const ConfigMap>>类型,默认构造后内部的shared_ptr是空指针。
  • 当set函数执行std::shared_ptr<const ConfigMap> blue = g_config.load();时,blue是空指针,后续执行std::make_shared<ConfigMap>(*blue)会直接解引用空指针,触发未定义行为(通常表现为程序崩溃退出),因此代码根本没走到打印那一步。
修复方案

1. 初始化原子共享指针

给Config添加构造函数,初始化g_config为指向空ConfigMap的shared_ptr:

Config() : g_config(std::make_shared<const ConfigMap>()) {}

2. 补充缺失的头文件

原代码使用了std::optional但未包含<optional>头文件,这会导致编译错误(部分编译器可能隐式包含,但标准要求显式引入),需要添加:

#include <optional>

修复后的完整代码

#include <iostream>
#include <map>
#include <string>
#include <atomic>
#include <memory>
#include <optional>
#include <thread>

struct Config {
    using ConfigMap = std::map<std::string, std::string>;

    std::atomic<std::shared_ptr<const ConfigMap>> g_config;

    // 初始化原子共享指针
    Config() : g_config(std::make_shared<const ConfigMap>()) {}

    void set(const std::string& key, const std::string& value) {
        std::shared_ptr<const ConfigMap> blue = g_config.load();
        std::shared_ptr<ConfigMap> green = std::make_shared<ConfigMap>(*blue);
        std::cerr << "This is not printing to the console" << std::endl << std::flush;
        (*green)[key] = value;
        // 将可修改的shared_ptr转为const版本后存储
        g_config.store(std::static_pointer_cast<const ConfigMap>(std::move(green)));
    }

    std::optional<std::string> get(const std::string& key) {
        std::shared_ptr<const ConfigMap> blue = g_config.load();
        auto valueIter = blue->find(key);
        if (valueIter != blue->end()) {
            return valueIter->second;
        }
        return std::nullopt;
    }
};

int main() {
    std::cout << "Main starting" << std::endl;

    Config config;
    std::string key = "default.hostname";
    std::string value = "example.com";

    std::thread setThread([&config, &key, &value]() {
        config.set(key, value);
        std::cout << "Set thread completed" << std::endl;
    });

    setThread.join();

    std::optional<std::string> hostnameOpt = config.get("default.hostname");
    if (hostnameOpt) {
        std::cout << "Default Hostname: " << *hostnameOpt << std::endl;
    } else {
        std::cout << "Default Hostname not set" << std::endl;
    }

    return 0;
}
蓝绿模式适配要点(针对单写线程场景)
  • 因为你只有一个写入线程,无需处理多写竞争的情况,蓝绿模式的核心逻辑(复制原对象→修改新对象→原子替换指针)可以安全工作。
  • 原子shared_ptr的load和store操作默认使用std::memory_order_seq_cst,这在单写多读场景下足够保证内存可见性,所有读线程能立即看到最新的配置。
  • 注意每次修改都要复制整个map,如果map体积较大,会带来一定的性能开销,这是无锁方案的典型 trade-off。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 07:37:29