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
相关推荐
EnigmaCoder14 小时前
【C++期末大作业】图书管理系统(面向对象+STL+数据持久化)
开发语言·c++·课程设计
云雾J视界14 小时前
告别重复编码:Boost.Optional、Variant和Assign如何提升C++工程可维护性?
c++·自动驾驶·分布式系统·variant·工具链·boost.optional·assign
w陆压1 天前
2.区分C++中相似但不同的类型
c++·c++基础知识
十五年专注C++开发1 天前
CMake进阶:vcpkg中OpenSSLConfig.cmake详解
c++·windows·cmake·openssl·跨平台编译
郑同学的笔记1 天前
【Eigen教程02】深入Eigen矩阵引擎:模板参数、内存布局与基础操作指南
c++·线性代数·矩阵·eigen
wadesir1 天前
C++基本数据类型详解(零基础掌握C++核心数据类型)
java·开发语言·c++
leiming61 天前
c++ map容器
开发语言·c++·算法
杨校1 天前
杨校老师课堂备赛C++信奥之模拟算法习题专项训练
开发语言·c++·算法
hd51cc1 天前
MFC 文档/视图 二
c++·mfc