Epoch / QSBR 内存回收解决ABA问题

✅ MPMC 无锁队列(Michael--Scott)

✅ Epoch / QSBR 内存回收

✅ 解决 ABA

✅ 多生产者 / 多消费者测试

✅ C++17,一条 g++ 命令即可跑

我刻意压缩到"教学 + 工程平衡点":

不是最极限性能,但逻辑完整、不会 UAF、不会 ABA,非常适合你现在的理解阶段。

cpp 复制代码
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
#include <cassert>
#include <chrono>

// ============================================================
// 1. Epoch / QSBR 实现
// ============================================================

class EpochManager {
public:
    static constexpr size_t MAX_THREADS = 64;

    struct ThreadEpoch {
        std::atomic<uint64_t> epoch;
        std::atomic<bool> active;
    };

    static EpochManager& instance() {
        static EpochManager inst;
        return inst;
    }

    size_t register_thread() {
        for (size_t i = 0; i < MAX_THREADS; ++i) {
            bool expected = false;
            if (threads_[i].active.compare_exchange_strong(expected, true)) {
                threads_[i].epoch.store(global_epoch_.load(std::memory_order_relaxed),
                                        std::memory_order_relaxed);
                return i;
            }
        }
        throw std::runtime_error("Too many threads");
    }

    void unregister_thread(size_t tid) {
        threads_[tid].active.store(false, std::memory_order_release);
    }

    void enter(size_t tid) {
        threads_[tid].epoch.store(global_epoch_.load(std::memory_order_acquire),
                                  std::memory_order_release);
    }

    void exit(size_t /*tid*/) {
        // QSBR: no-op
    }

    void advance_epoch() {
        global_epoch_.fetch_add(1, std::memory_order_acq_rel);
    }

    bool can_reclaim(uint64_t retire_epoch) {
        for (auto& t : threads_) {
            if (t.active.load(std::memory_order_acquire) &&
                t.epoch.load(std::memory_order_acquire) <= retire_epoch) {
                return false;
            }
        }
        return true;
    }

    uint64_t current_epoch() const {
        return global_epoch_.load(std::memory_order_acquire);
    }

private:
    EpochManager() {
        for (auto& t : threads_) {
            t.active.store(false);
            t.epoch.store(0);
        }
    }

    std::atomic<uint64_t> global_epoch_{1};
    ThreadEpoch threads_[MAX_THREADS];
};

// ============================================================
// 2. Epoch Reclaimer
// ============================================================

template<typename T>
class EpochReclaimer {
public:
    void retire(T* ptr) {
        retired_.push_back({ptr, EpochManager::instance().current_epoch()});
        if (retired_.size() >= 32)
            try_reclaim();
    }

    void try_reclaim() {
        auto& mgr = EpochManager::instance();
        auto it = retired_.begin();
        while (it != retired_.end()) {
            if (mgr.can_reclaim(it->epoch)) {
                delete it->ptr;
                it = retired_.erase(it);
            } else {
                ++it;
            }
        }
    }

private:
    struct Retired {
        T* ptr;
        uint64_t epoch;
    };
    std::vector<Retired> retired_;
};

// ============================================================
// 3. MPMC Lock-Free Queue (Michael--Scott + Epoch)
// ============================================================

template<typename T>
class MPMCQueue {
private:
    struct Node {
        T data;
        std::atomic<Node*> next;
        Node() : next(nullptr) {}
        Node(const T& v) : data(v), next(nullptr) {}
    };

    std::atomic<Node*> head_;
    std::atomic<Node*> tail_;
    EpochReclaimer<Node> reclaimer_;

public:
    MPMCQueue() {
        Node* dummy = new Node();
        head_.store(dummy, std::memory_order_relaxed);
        tail_.store(dummy, std::memory_order_relaxed);
    }

    ~MPMCQueue() {
        T tmp;
        while (dequeue(tmp)) {}
        delete head_.load();
    }

    void enqueue(const T& value, size_t tid) {
        EpochManager::instance().enter(tid);

        Node* node = new Node(value);

        while (true) {
            Node* last = tail_.load(std::memory_order_acquire);
            Node* next = last->next.load(std::memory_order_acquire);

            if (last == tail_.load(std::memory_order_acquire)) {
                if (next == nullptr) {
                    if (last->next.compare_exchange_weak(
                            next, node,
                            std::memory_order_release,
                            std::memory_order_relaxed)) {
                        tail_.compare_exchange_weak(
                            last, node,
                            std::memory_order_release,
                            std::memory_order_relaxed);
                        break;
                    }
                } else {
                    tail_.compare_exchange_weak(
                        last, next,
                        std::memory_order_release,
                        std::memory_order_relaxed);
                }
            }
        }

        EpochManager::instance().exit(tid);
    }

    bool dequeue(T& result, size_t tid) {
        EpochManager::instance().enter(tid);

        while (true) {
            Node* first = head_.load(std::memory_order_acquire);
            Node* last  = tail_.load(std::memory_order_acquire);
            Node* next  = first->next.load(std::memory_order_acquire);

            if (first == head_.load(std::memory_order_acquire)) {
                if (first == last) {
                    if (next == nullptr) {
                        EpochManager::instance().exit(tid);
                        return false;
                    }
                    tail_.compare_exchange_weak(
                        last, next,
                        std::memory_order_release,
                        std::memory_order_relaxed);
                } else {
                    result = next->data;
                    if (head_.compare_exchange_weak(
                            first, next,
                            std::memory_order_release,
                            std::memory_order_relaxed)) {
                        reclaimer_.retire(first);
                        EpochManager::instance().advance_epoch();
                        EpochManager::instance().exit(tid);
                        return true;
                    }
                }
            }
        }
    }
};

// ============================================================
// 4. 测试程序(MPMC)
// ============================================================

int main() {
    constexpr int PRODUCERS = 4;
    constexpr int CONSUMERS = 4;
    constexpr int ITEMS_PER_PRODUCER = 100000;

    MPMCQueue<int> queue;
    std::atomic<int> produced{0};
    std::atomic<int> consumed{0};

    std::vector<std::thread> threads;

    // Producers
    for (int i = 0; i < PRODUCERS; ++i) {
        threads.emplace_back([&queue, &produced]() {
            size_t tid = EpochManager::instance().register_thread();
            for (int n = 0; n < ITEMS_PER_PRODUCER; ++n) {
                queue.enqueue(n, tid);
                produced.fetch_add(1, std::memory_order_relaxed);
            }
            EpochManager::instance().unregister_thread(tid);
        });
    }

    // Consumers
    for (int i = 0; i < CONSUMERS; ++i) {
        threads.emplace_back([&queue, &consumed, &produced]() {
            size_t tid = EpochManager::instance().register_thread();
            int value;
            while (true) {
                if (queue.dequeue(value, tid)) {
                    consumed.fetch_add(1, std::memory_order_relaxed);
                } else {
                    if (consumed.load() >= PRODUCERS * ITEMS_PER_PRODUCER)
                        break;
                    std::this_thread::yield();
                }
            }
            EpochManager::instance().unregister_thread(tid);
        });
    }

    for (auto& t : threads)
        t.join();

    std::cout << "Produced: " << produced.load() << "\n";
    std::cout << "Consumed: " << consumed.load() << "\n";
    std::cout << "Done.\n";
}
bash 复制代码
g++ -std=c++17 -O2 -pthread epoch_mpmc.cpp -o epoch_mpmc
./epoch_mpmc
相关推荐
澈2073 小时前
深入浅出C++滑动窗口算法:原理、实现与实战应用详解
数据结构·c++·算法
A.A呐3 小时前
【C++第二十九章】IO流
开发语言·c++
ambition202424 小时前
从暴力搜索到理论最优:一道任务调度问题的完整算法演进历程
c语言·数据结构·c++·算法·贪心算法·深度优先
kebeiovo4 小时前
atomic原子操作实现无锁队列
服务器·c++
Yungoal4 小时前
常见 时间复杂度计算
c++·算法
6Hzlia4 小时前
【Hot 100 刷题计划】 LeetCode 48. 旋转图像 | C++ 矩阵变换题解
c++·leetcode·矩阵
Ricky_Theseus5 小时前
C++右值引用
java·开发语言·c++
吴梓穆6 小时前
UE5 c++ 常用方法
java·c++·ue5
云栖梦泽6 小时前
Linux内核与驱动:9.Linux 驱动 API 封装
linux·c++
Morwit6 小时前
【力扣hot100】 1. 两数之和
数据结构·c++·算法·leetcode·职场和发展