使用Boost实现一个线程安全的map

肯定还是成熟的库更合适

# Thread-Safe Ordered Map in Boost

Unfortunately, **Boost does not provide a built-in thread-safe ordered container** like `std::map`. Here's the breakdown:

## What Boost Offers

| Container | Thread-Safe | Ordered |
|-----------|-------------|---------|
| `boost::concurrent_flat_map` (1.83+) | ✅ | ❌ (hash-based) |
| `boost::container::flat_map` | ❌ | ✅ |
| `boost::multi_index_container` | ❌ | ✅ |

## Recommended Solution: Wrap `std::map` with `boost::shared_mutex`

For an order book where you need **ordering** (bids descending, asks ascending), the practical approach is to use a synchronized wrapper:

```cpp
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <map>
#include <functional>
#include <optional>

template<typename Key, typename Value, typename Compare = std::less<Key>>
class ThreadSafeOrderedMap {
private:
    mutable boost::shared_mutex m_mutex;
    std::map<Key, Value, Compare> m_map;

public:
    // Write operations - exclusive lock
    void insert(const Key& key, const Value& value) {
        boost::unique_lock<boost::shared_mutex> lock(m_mutex);
        m_map[key] = value;
    }

    bool erase(const Key& key) {
        boost::unique_lock<boost::shared_mutex> lock(m_mutex);
        return m_map.erase(key) > 0;
    }

    // Read operations - shared lock
    std::optional<Value> find(const Key& key) const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        auto it = m_map.find(key);
        if (it != m_map.end()) {
            return it->second;
        }
        return std::nullopt;
    }

    bool contains(const Key& key) const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        return m_map.find(key) != m_map.end();
    }

    bool empty() const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        return m_map.empty();
    }

    size_t size() const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        return m_map.size();
    }

    // Get first element (best bid/ask)
    std::optional<std::pair<Key, Value>> front() const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        if (m_map.empty()) return std::nullopt;
        return *m_map.begin();
    }

    // Atomic read-modify-write operations
    template<typename Func>
    bool modify(const Key& key, Func&& func) {
        boost::unique_lock<boost::shared_mutex> lock(m_mutex);
        auto it = m_map.find(key);
        if (it != m_map.end()) {
            func(it->second);
            return true;
        }
        return false;
    }

    // Get or create entry atomically
    template<typename Func>
    void getOrInsertAndModify(const Key& key, Func&& func) {
        boost::unique_lock<boost::shared_mutex> lock(m_mutex);
        func(m_map[key]);
    }

    // Remove if condition is met (e.g., empty price level)
    template<typename Predicate>
    bool eraseIf(const Key& key, Predicate&& pred) {
        boost::unique_lock<boost::shared_mutex> lock(m_mutex);
        auto it = m_map.find(key);
        if (it != m_map.end() && pred(it->second)) {
            m_map.erase(it);
            return true;
        }
        return false;
    }

    // Iterate with shared lock (for snapshots)
    template<typename Func>
    void forEach(Func&& func) const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        for (const auto& [key, value] : m_map) {
            func(key, value);
        }
    }

    // Get snapshot of top N levels
    std::vector<std::pair<Key, Value>> getTopN(size_t n) const {
        boost::shared_lock<boost::shared_mutex> lock(m_mutex);
        std::vector<std::pair<Key, Value>> result;
        result.reserve(std::min(n, m_map.size()));
        
        size_t count = 0;
        for (const auto& entry : m_map) {
            if (count++ >= n) break;
            result.push_back(entry);
        }
        return result;
    }
};

Updated Order Book Implementation

#include <cstdint>

// Your existing structs (unchanged)
struct SpecificOrder {
    uint64_t orderId;
    uint64_t price;
    uint64_t volume;
    int side;
    int updateTime;
    bool isValid;

    SpecificOrder() : orderId(0), price(0), volume(0), side(0), updateTime(0), isValid(false) {}
    SpecificOrder(uint64_t id, uint64_t p, uint64_t vol, int s, int time)
        : orderId(id), price(p), volume(vol), side(s), updateTime(time), isValid(true) {}
};

struct PriceLevel {
    uint64_t price;
    uint64_t totalVolume;
    std::map<uint64_t, SpecificOrder> orders;

    PriceLevel() : price(0), totalVolume(0) {}

    void AddOrder(const SpecificOrder& order) {
        orders[order.orderId] = order;
        totalVolume += order.volume;
    }

    bool RemoveOrder(uint64_t orderId, uint64_t& removedVolume) {
        auto it = orders.find(orderId);
        if (it != orders.end()) {
            removedVolume = it->second.volume;
            totalVolume -= removedVolume;
            orders.erase(it);
            return true;
        }
        return false;
    }

    bool UpdateOrder(uint64_t orderId, uint64_t newVolume) {
        auto it = orders.find(orderId);
        if (it != orders.end()) {
            uint64_t oldVolume = it->second.volume;
            it->second.volume = newVolume;
            totalVolume = totalVolume - oldVolume + newVolume;
            return true;
        }
        return false;
    }

    bool Empty() const { return orders.empty(); }
};

// Thread-safe order book
class OrderBook {
private:
    // Bids: descending order (highest price first)
    ThreadSafeOrderedMap<uint64_t, PriceLevel, std::greater<uint64_t>> m_bids;
    
    // Asks: ascending order (lowest price first)
    ThreadSafeOrderedMap<uint64_t, PriceLevel, std::less<uint64_t>> m_asks;

public:
    void AddOrder(const SpecificOrder& order) {
        auto& book = (order.side == 0) ? m_bids : m_asks;  // 0 = buy, 1 = sell
        
        book.getOrInsertAndModify(order.price, [&](PriceLevel& level) {
            level.price = order.price;
            level.AddOrder(order);
        });
    }

    bool RemoveOrder(uint64_t price, uint64_t orderId, int side) {
        auto& book = (side == 0) ? m_bids : m_asks;
        uint64_t removedVolume = 0;
        
        bool removed = book.modify(price, [&](PriceLevel& level) {
            level.RemoveOrder(orderId, removedVolume);
        });
        
        // Clean up empty price levels
        if (removed) {
            book.eraseIf(price, [](const PriceLevel& level) {
                return level.Empty();
            });
        }
        return removed;
    }

    bool UpdateOrder(uint64_t price, uint64_t orderId, uint64_t newVolume, int side) {
        auto& book = (side == 0) ? m_bids : m_asks;
        return book.modify(price, [&](PriceLevel& level) {
            level.UpdateOrder(orderId, newVolume);
        });
    }

    // Get best bid (highest buy price)
    std::optional<PriceLevel> GetBestBid() const {
        auto result = m_bids.front();
        return result ? std::optional<PriceLevel>(result->second) : std::nullopt;
    }

    // Get best ask (lowest sell price)
    std::optional<PriceLevel> GetBestAsk() const {
        auto result = m_asks.front();
        return result ? std::optional<PriceLevel>(result->second) : std::nullopt;
    }

    // Get market depth snapshot
    std::pair<std::vector<std::pair<uint64_t, PriceLevel>>,
              std::vector<std::pair<uint64_t, PriceLevel>>> 
    GetDepth(size_t levels) const {
        return {m_bids.getTopN(levels), m_asks.getTopN(levels)};
    }
};

Alternative: High-Performance Options

If you need higher performance for HFT-style order books:

Library Container Notes
Intel TBB tbb::concurrent_map Ordered, concurrent, skip-list based
libcds cds::container::SkipListMap Lock-free ordered map
folly folly::ConcurrentSkipList Facebook's high-perf skip list
// Example with Intel TBB (if you're open to non-Boost)
#include <tbb/concurrent_map.h>

tbb::concurrent_map<uint64_t, PriceLevel, std::greater<uint64_t>> m_bids;
tbb::concurrent_map<uint64_t, PriceLevel> m_asks;

Summary

Bottom line: For a thread-safe ordered map from Boost, use std::map + boost::shared_mutex as shown above. This provides:

  • ✅ Maintained ordering (ascending/descending)
  • ✅ Thread-safe concurrent access
  • ✅ Reader-writer lock efficiency (multiple readers, single writer)
  • ✅ Atomic compound operations via lambdas
posted @ 2025-12-03 14:00  Mr42Sir  阅读(5)  评论(0)    收藏  举报