MPSC队列

AI实现 尚未人工认证测试

1. 基于互斥锁和条件变量的实现(最常用)

#include <queue>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <optional>
#include <chrono>
#include <memory>

template<typename T>
class MPSCQueue {
public:
    explicit MPSCQueue(size_t capacity = 0) 
        : capacity_(capacity), is_closed_(false) {}
    
    ~MPSCQueue() {
        close();
    }
    
    // 生产者:推送数据(阻塞直到成功或超时)
    template<typename U>
    bool push(U&& item, std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) {
        std::unique_lock<std::mutex> lock(mutex_);
        
        // 如果有容量限制,等待队列有空闲空间
        if (capacity_ > 0) {
            if (timeout.count() > 0) {
                if (!not_full_.wait_for(lock, timeout, [this]() { 
                    return queue_.size() < capacity_ || is_closed_; 
                })) {
                    return false; // 超时
                }
            } else {
                not_full_.wait(lock, [this]() { 
                    return queue_.size() < capacity_ || is_closed_; 
                });
            }
        }
        
        if (is_closed_) return false;
        
        queue_.push(std::forward<U>(item));
        lock.unlock();
        not_empty_.notify_one();
        return true;
    }
    
    // 生产者:尝试推送数据(非阻塞)
    template<typename U>
    bool try_push(U&& item) {
        std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
        if (!lock.owns_lock()) return false;
        
        if (is_closed_ || (capacity_ > 0 && queue_.size() >= capacity_)) {
            return false;
        }
        
        queue_.push(std::forward<U>(item));
        lock.unlock();
        not_empty_.notify_one();
        return true;
    }
    
    // 消费者:弹出数据(阻塞直到有数据或队列关闭)
    std::optional<T> pop(std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) {
        std::unique_lock<std::mutex> lock(mutex_);
        
        if (timeout.count() > 0) {
            if (!not_empty_.wait_for(lock, timeout, [this]() { 
                return !queue_.empty() || is_closed_; 
            })) {
                return std::nullopt; // 超时
            }
        } else {
            not_empty_.wait(lock, [this]() { 
                return !queue_.empty() || is_closed_; 
            });
        }
        
        if (queue_.empty()) return std::nullopt;
        
        T item = std::move(queue_.front());
        queue_.pop();
        
        lock.unlock();
        if (capacity_ > 0) {
            not_full_.notify_one();
        }
        
        return std::move(item);
    }
    
    // 消费者:尝试弹出数据(非阻塞)
    std::optional<T> try_pop() {
        std::unique_lock<std::mutex> lock(mutex_, std::try_to_lock);
        if (!lock.owns_lock() || queue_.empty()) {
            return std::nullopt;
        }
        
        T item = std::move(queue_.front());
        queue_.pop();
        
        lock.unlock();
        if (capacity_ > 0) {
            not_full_.notify_one();
        }
        
        return std::move(item);
    }
    
    // 关闭队列,唤醒所有等待的线程
    void close() {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            is_closed_ = true;
        }
        not_empty_.notify_all();
        not_full_.notify_all();
    }
    
    // 队列是否已关闭
    bool is_closed() const {
        return is_closed_.load(std::memory_order_acquire);
    }
    
    // 获取队列大小
    size_t size() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.size();
    }
    
    // 队列是否为空
    bool empty() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return queue_.empty();
    }
    
private:
    mutable std::mutex mutex_;
    std::condition_variable not_empty_;
    std::condition_variable not_full_;
    std::queue<T> queue_;
    const size_t capacity_;
    std::atomic<bool> is_closed_;
};

2. 无锁实现(更高性能)

#include <atomic>
#include <memory>
#include <optional>

// 无锁MPSC队列节点
template<typename T>
struct LockFreeNode {
    T data;
    std::atomic<LockFreeNode<T>*> next;
    
    explicit LockFreeNode(T&& val) 
        : data(std::move(val)), next(nullptr) {}
    
    explicit LockFreeNode(const T& val) 
        : data(val), next(nullptr) {}
};

template<typename T>
class LockFreeMPSCQueue {
public:
    LockFreeMPSCQueue() {
        // 创建dummy节点
        auto dummy = new LockFreeNode<T>(T{});
        head_.store(dummy, std::memory_order_relaxed);
        tail_.store(dummy, std::memory_order_relaxed);
    }
    
    ~LockFreeMPSCQueue() {
        // 清理所有节点
        while (auto node = head_.load(std::memory_order_relaxed)) {
            head_.store(node->next.load(std::memory_order_relaxed), std::memory_order_relaxed);
            delete node;
        }
    }
    
    // 生产者:推送数据(无锁)
    template<typename U>
    void push(U&& item) {
        auto new_node = new LockFreeNode<T>(std::forward<U>(item));
        
        // 获取当前tail
        auto tail = tail_.load(std::memory_order_relaxed);
        
        // CAS循环直到成功
        LockFreeNode<T>* expected = nullptr;
        do {
            expected = nullptr;
            tail = tail_.load(std::memory_order_relaxed);
        } while (!tail->next.compare_exchange_weak(
            expected, 
            new_node,
            std::memory_order_release,
            std::memory_order_relaxed));
        
        // 更新tail
        tail_.store(new_node, std::memory_order_release);
    }
    
    // 消费者:弹出数据
    std::optional<T> pop() {
        auto head = head_.load(std::memory_order_relaxed);
        auto next = head->next.load(std::memory_order_acquire);
        
        if (next == nullptr) {
            return std::nullopt;
        }
        
        // 获取数据
        T data = std::move(next->data);
        
        // 更新head
        head_.store(next, std::memory_order_release);
        
        // 删除旧节点
        delete head;
        
        return std::move(data);
    }
    
    // 队列是否为空
    bool empty() const {
        auto head = head_.load(std::memory_order_acquire);
        return head->next.load(std::memory_order_acquire) == nullptr;
    }
    
private:
    alignas(64) std::atomic<LockFreeNode<T>*> head_;  // 消费者使用
    alignas(64) std::atomic<LockFreeNode<T>*> tail_;  // 生产者使用
};

3. 环形缓冲区实现(固定大小,高性能)

#include <vector>
#include <atomic>
#include <optional>
#include <thread>

template<typename T>
class RingBufferMPSCQueue {
public:
    explicit RingBufferMPSCQueue(size_t capacity)
        : capacity_(capacity),
          buffer_(capacity),
          head_(0),
          tail_(0) {
        // 确保容量是2的幂,便于使用位运算
        if ((capacity & (capacity - 1)) != 0) {
            throw std::invalid_argument("Capacity must be power of two");
        }
    }
    
    // 生产者:推送数据
    template<typename U>
    bool push(U&& item) {
        const auto current_tail = tail_.load(std::memory_order_relaxed);
        const auto next_tail = increment(current_tail);
        
        // 检查是否已满
        if (next_tail == head_.load(std::memory_order_acquire)) {
            return false; // 队列已满
        }
        
        // 写入数据
        buffer_[current_tail & (capacity_ - 1)] = std::forward<U>(item);
        
        // 发布写入
        std::atomic_thread_fence(std::memory_order_release);
        tail_.store(next_tail, std::memory_order_release);
        
        return true;
    }
    
    // 生产者:批量推送
    template<typename Iterator>
    size_t push_bulk(Iterator begin, Iterator end) {
        size_t count = 0;
        for (auto it = begin; it != end; ++it) {
            if (!push(std::move(*it))) {
                break;
            }
            ++count;
        }
        return count;
    }
    
    // 消费者:弹出数据
    std::optional<T> pop() {
        const auto current_head = head_.load(std::memory_order_relaxed);
        
        // 检查是否为空
        if (current_head == tail_.load(std::memory_order_acquire)) {
            return std::nullopt;
        }
        
        // 读取数据
        T item = std::move(buffer_[current_head & (capacity_ - 1)]);
        
        // 发布读取
        std::atomic_thread_fence(std::memory_order_release);
        head_.store(increment(current_head), std::memory_order_release);
        
        return std::move(item);
    }
    
    // 消费者:批量弹出
    template<typename OutputIterator>
    size_t pop_bulk(OutputIterator output, size_t max_count) {
        size_t count = 0;
        while (count < max_count) {
            auto item = pop();
            if (!item) break;
            *output++ = std::move(*item);
            ++count;
        }
        return count;
    }
    
    // 队列是否为空
    bool empty() const {
        return head_.load(std::memory_order_acquire) == 
               tail_.load(std::memory_order_acquire);
    }
    
    // 队列是否已满
    bool full() const {
        const auto current_tail = tail_.load(std::memory_order_acquire);
        return increment(current_tail) == head_.load(std::memory_order_acquire);
    }
    
    // 队列大小
    size_t size() const {
        const auto head = head_.load(std::memory_order_acquire);
        const auto tail = tail_.load(std::memory_order_acquire);
        return (tail - head) & (capacity_ - 1);
    }
    
private:
    size_t increment(size_t index) const {
        return (index + 1) & (capacity_ - 1);
    }
    
    const size_t capacity_;
    std::vector<T> buffer_;
    alignas(64) std::atomic<size_t> head_;  // 消费者使用
    alignas(64) std::atomic<size_t> tail_;  // 生产者使用
};

4. 使用示例

#include <iostream>
#include <thread>
#include <vector>
#include <chrono>

void test_mpsc_queue() {
    // 测试有锁版本
    MPSCQueue<int> queue(100);  // 容量100
    
    std::atomic<int> producer_count{0};
    std::atomic<int> consumer_count{0};
    
    // 启动多个生产者
    std::vector<std::thread> producers;
    for (int i = 0; i < 3; ++i) {
        producers.emplace_back([i, &queue, &producer_count]() {
            for (int j = 0; j < 100; ++j) {
                int value = i * 100 + j;
                if (queue.push(value)) {
                    producer_count.fetch_add(1, std::memory_order_relaxed);
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
        });
    }
    
    // 启动单个消费者
    std::thread consumer([&queue, &consumer_count]() {
        while (true) {
            auto item = queue.pop(std::chrono::milliseconds(100));
            if (!item) {
                // 检查是否所有生产者都结束了
                if (queue.is_closed()) break;
                continue;
            }
            consumer_count.fetch_add(1, std::memory_order_relaxed);
            // 处理数据
            // std::cout << "Consumed: " << *item << std::endl;
        }
    });
    
    // 等待生产者结束
    for (auto& t : producers) {
        t.join();
    }
    
    // 关闭队列
    queue.close();
    
    // 等待消费者结束
    consumer.join();
    
    std::cout << "Produced: " << producer_count << std::endl;
    std::cout << "Consumed: " << consumer_count << std::endl;
}

void test_lockfree_mpsc_queue() {
    // 测试无锁版本
    LockFreeMPSCQueue<int> queue;
    
    std::vector<std::thread> producers;
    for (int i = 0; i < 3; ++i) {
        producers.emplace_back([i, &queue]() {
            for (int j = 0; j < 100; ++j) {
                queue.push(i * 100 + j);
            }
        });
    }
    
    // 等待生产者
    for (auto& t : producers) {
        t.join();
    }
    
    // 消费者消费所有数据
    int count = 0;
    while (auto item = queue.pop()) {
        ++count;
    }
    
    std::cout << "Lock-free queue consumed: " << count << " items" << std::endl;
}

int main() {
    std::cout << "Testing MPSC Queue with locks:" << std::endl;
    test_mpsc_queue();
    
    std::cout << "\nTesting Lock-free MPSC Queue:" << std::endl;
    test_lockfree_mpsc_queue();
    
    return 0;
}

5. 性能优化建议

  1. 缓存行对齐

    • 使用 alignas(64) 防止生产者之间的false sharing
  2. 内存分配优化

    // 使用内存池预分配节点
    template<typename T>
    class PooledMPSCQueue {
        // 实现节点池
    };
    
  3. 批量操作

    • 提供 push_bulkpop_bulk 减少锁开销
  4. 选择合适的实现

    • 低竞争场景:有锁队列简单可靠
    • 高吞吐场景:无锁队列性能更好
    • 固定大小需求:环形缓冲区最快

6. 测试代码

#include <iostream>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include <iomanip>
#include <algorithm>
#include <random>

// 包含我们之前实现的三种队列
#include "MPSC/MPSCQueue.h"  // 有锁队列
#include "MPSC/LockFreeMPSCQueue.h"  // 无锁队列
#include "MPSC/RingBufferMPSCQueue.h"// 环形缓冲区队列

using namespace std::chrono;

// ================= 性能测试 =================
template<typename Queue>
double test_MPSCqueue(int producers, int items_per_producer) {
    Queue queue;
    std::atomic<int> produced{0};
    std::atomic<int> consumed{0};
    std::atomic<bool> stop{false};

    // 启动生产者
    std::vector<std::thread> producer_threads;
    for (int i = 0; i < producers; ++i) {
        producer_threads.emplace_back([&, i]() {
            for (int j = 0; j < items_per_producer; ++j) {
                int value = i * items_per_producer + j;
                // queue.push(value);
                while (!queue.push(value)) {
                    std::this_thread::yield();
                }
                produced.fetch_add(1, std::memory_order_relaxed);
            }
        });
    }

    // 启动消费者
    std::thread consumer([&]() {
        while (consumed < producers * items_per_producer) {
            auto item = queue.pop();
            if (item) {
                consumed.fetch_add(1, std::memory_order_relaxed);
            } else {
                std::this_thread::yield();
            }
        }
        stop = true;
    });

    // 计时
    auto start = high_resolution_clock::now();

    // 等待生产者
    for (auto& t : producer_threads) {
        t.join();
    }

    // 等待消费者
    consumer.join();

    auto end = high_resolution_clock::now();

    double total_time = duration_cast<nanoseconds>(end - start).count() / 1e9;
    double total_items = producers * items_per_producer;

    return total_items / total_time; // 返回吞吐量 (items/sec)
}


template<typename Queue>
double test_LOCKFreequeue(int producers, int items_per_producer) {
    Queue queue;
    std::atomic<int> produced{0};
    std::atomic<int> consumed{0};
    std::atomic<bool> stop{false};

    // 启动生产者
    std::vector<std::thread> producer_threads;
    for (int i = 0; i < producers; ++i) {
        producer_threads.emplace_back([&, i]() {
            for (int j = 0; j < items_per_producer; ++j) {
                int value = i * items_per_producer + j;
                queue.push(value);
                // while (!queue.push(value)) {
                //     std::this_thread::yield();
                // }
                produced.fetch_add(1, std::memory_order_relaxed);
            }
        });
    }

    // 启动消费者
    std::thread consumer([&]() {
        while (consumed < producers * items_per_producer) {
            auto item = queue.pop();
            if (item) {
                consumed.fetch_add(1, std::memory_order_relaxed);
            } else {
                std::this_thread::yield();
            }
        }
        stop = true;
    });

    // 计时
    auto start = high_resolution_clock::now();

    // 等待生产者
    for (auto& t : producer_threads) {
        t.join();
    }

    // 等待消费者
    consumer.join();

    auto end = high_resolution_clock::now();

    double total_time = duration_cast<nanoseconds>(end - start).count() / 1e9;
    double total_items = producers * items_per_producer;

    return total_items / total_time; // 返回吞吐量 (items/sec)
}

template<typename Queue>
double test_RINGBUfferqueue(int producers, int items_per_producer) {
    Queue queue{2048};
    std::atomic<int> produced{0};
    std::atomic<int> consumed{0};
    std::atomic<bool> stop{false};

    // 启动生产者
    std::vector<std::thread> producer_threads;
    for (int i = 0; i < producers; ++i) {
        producer_threads.emplace_back([&, i]() {
            for (int j = 0; j < items_per_producer; ++j) {
                int value = i * items_per_producer + j;
                while (!queue.push(value)) {
                    std::this_thread::yield();
                }
                produced.fetch_add(1, std::memory_order_relaxed);
            }
        });
    }

    // 启动消费者
    std::thread consumer([&]() {
        while (consumed < producers * items_per_producer) {
            auto item = queue.pop();
            if (item) {
                consumed.fetch_add(1, std::memory_order_relaxed);
            } else {
                std::this_thread::yield();
            }
        }
        stop = true;
    });

    // 计时
    auto start = high_resolution_clock::now();

    // 等待生产者
    for (auto& t : producer_threads) {
        t.join();
    }

    // 等待消费者
    consumer.join();

    auto end = high_resolution_clock::now();

    double total_time = duration_cast<nanoseconds>(end - start).count() / 1e9;
    double total_items = producers * items_per_producer;

    return total_items / total_time; // 返回吞吐量 (items/sec)
}


int main() {
    std::cout << "========== MPSC队列简单性能测试 ==========\n";
    std::cout << "测试配置: 4个生产者,每个生产10万个项目\n\n";

    const int PRODUCERS = 4;
    const int ITEMS_PER_PRODUCER = 100000;

    std::cout << std::fixed << std::setprecision(2);

    try {
        // 测试有锁队列
        std::cout << "1. 测试有锁队列...\n";
        double locked_throughput = test_MPSCqueue<MPSCQueue<int>>(PRODUCERS, ITEMS_PER_PRODUCER);
        std::cout << "   吞吐量: " << locked_throughput / 1000 << " K items/sec\n\n";

        // 测试无锁队列
        std::cout << "2. 测试无锁队列...\n";
        /* 可能存在死锁 */
        double lockfree_throughput = test_LOCKFreequeue<LockFreeMPSCQueue<int>>(PRODUCERS, ITEMS_PER_PRODUCER);
        std::cout << "   吞吐量: " << lockfree_throughput / 1000 << " K items/sec\n\n";

        // // 测试环形缓冲区队列
        // std::cout << "3. 测试环形缓冲区队列...\n";
        double ringbuffer_throughput = test_RINGBUfferqueue<RingBufferMPSCQueue<int>>(PRODUCERS, ITEMS_PER_PRODUCER);
        std::cout << "   吞吐量: " << ringbuffer_throughput / 1000 << " K items/sec\n\n";

        // 性能对比
        std::cout << "========== 性能对比 ==========\n";
        std::cout << std::setw(20) << "队列类型"
                  << std::setw(20) << "吞吐量(K/s)"
                  << std::setw(20) << "相对性能" << "\n";
        std::cout << std::string(60, '-') << "\n";

        double max_throughput = std::max({lockfree_throughput, locked_throughput,ringbuffer_throughput});
            // std::max({locked_throughput} /* ringbuffer_throughput}*/);

        auto print_row = [&](const std::string& name, double throughput) {
            std::cout << std::setw(20) << name
                      << std::setw(20) << throughput / 1000
                      << std::setw(20) << (throughput / max_throughput * 100) << "%\n";
        };

        print_row("有锁队列", locked_throughput);
        print_row("无锁队列", lockfree_throughput);
        print_row("环形缓冲区", ringbuffer_throughput);

        std::cout << "\n";

        // 结论
        // std::cout << "========== 结论 ==========\n";
        // if (ringbuffer_throughput > lockfree_throughput && ringbuffer_throughput > locked_throughput) {
        //     std::cout << "✓ 环形缓冲区性能最佳,适合MPSC场景\n";
        // } else if (lockfree_throughput > locked_throughput) {
        //     std::cout << "✓ 无锁队列性能较好,适合高并发场景\n";
        // } else {
        //     std::cout << "✓ 有锁队列简单可靠,适合低并发场景\n";
        // }

    } catch (const std::exception& e) {
        std::cerr << "测试错误: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
posted @ 2025-12-25 15:25  BlackSnow  阅读(7)  评论(0)    收藏  举报