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

Lock-free可交换对象池缓存:运行时池交换下无锁get、recycle操作实现咨询

现有实现的核心缺陷

你当前的代码存在一个致命的生命周期安全问题:_atomicDefaultRulePool存储的是PreparedRulePool的裸指针,你在atomicSwapPool中替换原子指针后直接销毁旧池所持有的shared_ptr,如果此时有其他线程已经加载了旧的裸指针、正在执行get或recycle逻辑,会直接访问野指针,导致程序崩溃。

可行的无锁实现方案

你不需要放弃无锁设计,只要调整生命周期管理逻辑即可解决问题:

  • 把_atomicDefaultRulePool的类型从std::atomic<裸指针>替换为std::atomic<std::shared_ptr<detail::PreparedRulePool<Data, Delegate>>>,C++20及以上标准原生支持该原子类型的无锁操作,低版本可引入Boost库的atomic_shared_ptr达到相同效果。
  • getPreparedDefaultRule接口直接原子加载shared_ptr,该操作会自动延长池的生命周期,哪怕加载后池立刻被替换,你手里的shared_ptr指向的旧池依然有效,调用内部无锁的getPreparedRule完全安全,全程没有加锁操作。
  • recyclePreparedDefaultRule接口同样先原子加载池的shared_ptr,你原有的tag匹配逻辑可以保留:如果当前池的tag和待回收对象的tag一致就回收到池,不一致直接让unique_ptr自动析构对象即可,旧池没有必要再回收对象,等所有持有的旧池shared_ptr都释放后,旧池会自动销毁。
  • 池替换逻辑直接用std::atomic_exchange操作原子shared_ptr即可,不需要单独维护额外的_defaultRulePool成员,原子shared_ptr本身会自动管理旧池的生命周期,不会提前销毁正在被使用的旧池。

修正后的代码示例

template <typename Data, typename Delegate>
class DefaultRulePoolCache {
public:
    DefaultRulePoolCache() = default;
    
    std::unique_ptr<detail::PreparedRule<Data, Delegate>> getPreparedDefaultRule() {
        // 原子加载共享指针,自动延长池生命周期,全程无锁
        auto current_pool = _atomicDefaultRulePool.load();
        if (!current_pool) {
            return nullptr;
        }
        return current_pool->getPreparedRule();
    }
    
    void recyclePreparedDefaultRule(std::unique_ptr<detail::PreparedRule<Data, Delegate>> preparedRule) {
        if (!preparedRule) {
            return;
        }
        // 原子加载共享指针,全程无锁
        auto current_pool = _atomicDefaultRulePool.load();
        if (!current_pool) {
            return;
        }
        // tag匹配才回收,否则直接释放对象
        if (current_pool->getTag() == preparedRule->getTag()) {
            current_pool->recyclePreparedRule(std::move(preparedRule));
        }
    }
    
    void setDefaultRulePool(std::shared_ptr<detail::PreparedRulePool<Data, Delegate>> defaultRulePool) {
        std::lock_guard<std::mutex> lock(_op_mutex);
        // 原子替换池,旧池会等所有引用释放后自动销毁
        _atomicDefaultRulePool.exchange(std::move(defaultRulePool));
    }
    
    void removeDefaultRulePool() {
        std::lock_guard<std::mutex> lock(_op_mutex);
        _atomicDefaultRulePool.exchange(nullptr);
    }

private:
    std::atomic<std::shared_ptr<detail::PreparedRulePool<Data, Delegate>>> _atomicDefaultRulePool{nullptr};
    // 仅用于保证set/remove操作的串行化,不影响get/recycle的无锁逻辑
    std::mutex _op_mutex;
};

如果你的编译环境不支持C++20的原子shared_ptr,可以把原子操作替换为std::atomic_load、std::atomic_exchange等自由函数操作非原子的shared_ptr成员,性能会略低但依然是线程安全的。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:36:03