使用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

浙公网安备 33010602011771号