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
相关推荐
czy87874757 小时前
深入了解 C++ 中的 `std::bind` 函数
开发语言·c++
我在人间贩卖青春7 小时前
C++之继承的方式
c++·private·public·protected·继承方式
智者知已应修善业9 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法
Trouvaille ~9 小时前
【Linux】应用层协议设计实战(一):自定义协议与网络计算器
linux·运维·服务器·网络·c++·http·应用层协议
CSCN新手听安9 小时前
【linux】高级IO,I/O多路转接之poll,接口和原理讲解,poll版本的TCP服务器
linux·运维·服务器·c++·计算机网络·高级io·poll
CSCN新手听安9 小时前
【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型
linux·服务器·网络·c++·tcp/ip·json
m0_736919109 小时前
C++中的委托构造函数
开发语言·c++·算法
小小小小王王王9 小时前
洛谷-P1886 【模板】单调队列 / 滑动窗口
c++·算法
历程里程碑10 小时前
Linux 库
java·linux·运维·服务器·数据结构·c++·算法
Sheep Shaun10 小时前
如何让一个进程诞生、工作、终止并等待回收?——探索Linux进程控制与Shell的诞生
linux·服务器·数据结构·c++·算法·shell·进程控制