返回题库

风险指针内存回收

Hazard Pointer Reclamation

专题
Systems & Architecture / 系统与架构
难度
L3
来源
MyntBit

题目详情

在低延迟量化交易系统中,无锁数据结构对最大化吞吐和最小化执行延迟至关重要。Hazard Pointer 提供安全内存回收策略,防止 ABA 问题和释放后使用错误。

任务:实现 Hazard Pointer 管理器类,维护每线程 hazard pointer 记录。线程访问共享节点前调用保护方法,离开后调用释放方法。仅无保护时才回收节点。

英文原题

In low-latency quantitative trading systems, lock-free data structures are essential for maximizing throughput and minimizing execution delays. Hazard pointers provide a safe memory reclamation strategy to prevent the ABA problem and use-after-free bugs by allowing threads to announce which memory addresses they are currently reading.
Task
Implement a HazardPointerManager class to simulate a hazard pointer memory reclamation strategy.
You must support the following operations:
void acquire(in

解析

问题分析

风险指针(Hazard Pointer)是无锁数据结构中安全回收内存的技术。读者线程在访问节点前将节点指针写入"风险指针"列表,回收线程仅释放不在任何风险指针列表中的节点。

实现

class HazardPointer {
    static constexpr int MAX_HP = 2;  // 每线程最多同时保护 2 个指针
    static thread_local std::atomic<void*> hp_[MAX_HP];
    static std::atomic<void*> retire_list_;
public:
    static void protect(int idx, void* ptr) { hp_[idx].store(ptr, std::memory_order_release); }
    static void clear(int idx) { hp_[idx].store(nullptr, std::memory_order_release); }
    static bool isProtected(void* ptr) {
        // 简化版:遍历全局线程列表(实际实现需维护线程注册表)
        return false;  // 需要完整实现
    }
};

复杂度与边界

  • 时间复杂度:protect/clear O(1),回收 O(R * N) R=活跃线程数 N=回收列表大小
  • 空间复杂度:O(线程数 * MAX_HP + 回收列表)
  • 边界条件:(1) 忘记 clear 导致节点永不被回收 (2) MAX_HP 限制同时保护的指针数 (3) 需要全局线程注册表

英文解析

Analysis

Hazard Pointers are a technique for safe memory reclamation in lock-free data structures. Reader threads register a node pointer in a "hazard pointer" list before accessing it, and the reclamation thread only frees nodes not present in any hazard pointer list.

Solution

class HazardPointer {
    static constexpr int MAX_HP = 2;
    static thread_local std::atomic<void*> hp_[MAX_HP];
    static std::atomic<void*> retire_list_;
public:
    static void protect(int idx, void* ptr) { hp_[idx].store(ptr, std::memory_order_release); }
    static void clear(int idx) { hp_[idx].store(nullptr, std::memory_order_release); }
    static bool isProtected(void* ptr) {
        // Simplified: traverse global thread list (production needs thread registry)
        return false;
    }
    static void retire(void* ptr) {
        // Add to retire list, scan and free unprotected nodes periodically
    }
};

Complexity & Edge Cases

  • Time complexity: protect/clear O(1), reclamation O(R x N) where R = active threads, N = retire list size
  • Space complexity: O(threads x MAX_HP + retire list)
  • Edge cases: (1) Forgetting to clear prevents node from ever being reclaimed (2) MAX_HP limits concurrent protected pointers per thread (3) Requires a global thread registry

Verification

Simulate concurrent read/write on a lock-free linked list: readers protect nodes with hazard pointers, writer removes nodes and retires them. Confirm no access to freed memory occurs.

Key Considerations

Hazard pointers offer bounded memory overhead compared to epoch-based reclamation. In trading systems where order book nodes are frequently removed and re-inserted, hazard pointers guarantee that a reader never accesses freed memory - critical for market data integrity.