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

如何为C++限价订单簿匹配函数实现参数化线程锁?

C++限价订单簿_match_orders多线程访问优化方案

核心需求

仅对同一个LimitLevel对象的_match_orders调用进行串行阻塞,不同LimitLevel对象的调用允许完全并发执行,既保证线程安全,又最大化多线程利用效率。

现有方案缺陷

  • 全局std::mutex导致所有调用串行,完全浪费多线程优势;
  • 用unordered_set记录占用价格+condition_variable的方案,频繁的集合读写会引入额外性能开销;
  • 为每个可能价格预创建mutex的方案,因价格范围达INT_MAX,资源开销完全不可接受。

最优解决方案:每个LimitLevel内置专属mutex

思路

由于LimitLevel仅在对应价格存在订单时才会创建(而非覆盖所有可能价格),给每个LimitLevel实例绑定一个专属std::mutex,既能实现精准的锁粒度(只保护需要同步的对象),又不会造成资源浪费。同时,用一个全局mutex专门保护共享的全局结构(如orders哈希表、bids/asks价格树),将锁的范围最小化。

代码修改步骤

  1. 修改LimitLevel类,添加专属mutex
    给LimitLevel增加私有mutex成员,并提供访问接口:

    class LimitLevel final {
        public:
            const int price;
            std::queue<int> *orders;
            int quantity;
    
            LimitLevel(Order *order) : price(order->price), quantity(order->quantity) {
                orders = new std::queue<int>();
                orders->push(order->id);
            }
    
            ~LimitLevel() {
                delete orders;
            }
    
            // 获取专属mutex的接口
            std::mutex& get_mutex() { return mtx; }
    
            // 原有方法保持不变
            inline void append(Order *order) { orders->push(order->id); }
            inline void append(int _id) { orders->push(_id); }
            inline int pop_left() {
                int val = orders->front();
                orders->pop();
                return val;
            }
            inline int get_head() {
                if (get_length()) {
                    return orders->front();
                } else {
                    throw std::length_error("Head attempted to be accessed from LimitLevel of length 0");
                }
            }
            inline int get_tail() {
                if (get_length()) {
                    return orders->back();
                } else {
                    throw std::length_error("Tail attempted to be accessed from LimitLevel of length 0");
                }
            }
            inline int get_length() { return orders->size(); }
    
        private:
            std::mutex mtx; // 每个LimitLevel的专属锁,保护自身的orders队列和quantity
    };
    
  2. 重构_match_orders函数的锁逻辑
    替换全局锁为LimitLevel专属锁,仅在访问全局共享结构时使用全局mutex,并最小化全局锁的持有时间:

    void _match_orders(Order *order, LimitLevel *best_value) {
        if (best_value == nullptr) {
            return;
        }
    
        // 锁定当前操作的LimitLevel:同LimitLevel串行,不同的并行
        std::lock_guard<std::mutex> level_lock(best_value->get_mutex());
    
        while (best_value->quantity > 0 && order->quantity > 0 && best_value->get_length() > 0) {
            int head_order_id = best_value->get_head();
            Order* head_order = nullptr;
    
            // 第一步:访问全局orders哈希表,处理订单数量更新
            {
                std::lock_guard<std::mutex> global_lock(mtx);
                auto it = orders.find(head_order_id);
                if (it == orders.end()) {
                    // 订单已被删除,直接移除队列头部
                    best_value->pop_left();
                    continue;
                }
                head_order = it->second;
                // 计算交易数量
                int trade_qty = std::min(order->quantity, head_order->quantity);
                // 更新订单和LimitLevel的数量
                order->quantity -= trade_qty;
                head_order->quantity -= trade_qty;
                best_value->quantity -= trade_qty;
            } // 全局锁自动释放
    
            // 第二步:处理订单完成或LimitLevel清空的收尾逻辑
            {
                std::lock_guard<std::mutex> global_lock(mtx);
                if (order->quantity == 0 && orders.count(order->id)) {
                    cancel(order->id); // 确保cancel内部也使用全局锁保护共享结构
                }
                
                if (head_order->quantity == 0 && orders.count(head_order_id)) {
                    _pop_limit(best_value); // _pop_limit需保证线程安全,操作bids/asks时用全局锁
                    orders.erase(head_order_id);
                }
                
                if (best_value->quantity == 0) {
                    std::map<int, LimitLevel*> *order_tree = _get_side(!(order->is_bid));
                    if (order_tree->count(best_value->price)) {
                        order_tree->erase(best_value->price);
                    }
                }
            } // 全局锁自动释放
        }
    }
    
  3. 配套修改辅助函数
    确保cancel、_pop_limit等修改全局共享结构的函数内部,都使用全局mutex(即原有的mtx)来保护操作,避免线程安全问题。

关键注意事项

  • 锁顺序一致性:所有线程必须遵循「先获取LimitLevel锁,再获取全局锁」的顺序,避免死锁;
  • 最小化锁持有时间:将全局锁的持有范围压缩到仅必要的共享结构访问操作,减少锁竞争;
  • Order对象的线程安全:Order的quantity修改必须在全局锁保护下,因为多个线程可能同时访问同一个Order实例;
  • 异常安全:使用std::lock_guard自动管理锁的释放,避免因异常导致锁泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:59:55