侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1824 篇文章
  • 累计收到 0 条评论

设计线程安全的环形缓冲区(Ring Buffer)类,使用智能指针管理内存,支持多生产者多消费者场景

2025-12-11 / 0 评论 / 4 阅读

题目

设计线程安全的环形缓冲区(Ring Buffer)类,使用智能指针管理内存,支持多生产者多消费者场景

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

智能指针内存管理, 多线程同步, 环形缓冲区设计, 循环引用避免, 异常安全

快速回答

实现要点:

  • 使用std::unique_ptr管理缓冲区内存,避免手动delete
  • 通过std::mutexstd::condition_variable实现线程同步
  • 环形缓冲区使用模运算处理索引回绕
  • 生产者和消费者线程使用双重检查避免虚假唤醒
  • 禁用拷贝构造/赋值,防止智能指针意外共享
  • 使用std::weak_ptr打破可能的循环引用(如回调场景)
## 解析

核心原理

环形缓冲区是高效的生产者-消费者模型数据结构,需解决:1) 线程安全的并发访问 2) 内存自动管理 3) 索引边界处理。智能指针确保异常安全,避免内存泄漏。

代码实现

#include <memory>
#include <mutex>
#include <condition_variable>

template<typename T>
class ThreadSafeRingBuffer {
public:
    explicit ThreadSafeRingBuffer(size_t capacity) 
        : buffer_(std::make_unique<T[]>(capacity)), 
          capacity_(capacity) {}

    // 禁用拷贝
    ThreadSafeRingBuffer(const ThreadSafeRingBuffer&) = delete;
    ThreadSafeRingBuffer& operator=(const ThreadSafeRingBuffer&) = delete;

    void push(T item) {
        std::unique_lock<std::mutex> lock(mutex_);
        not_full_.wait(lock, [this] { return count_ < capacity_; });

        buffer_[(head_ + count_) % capacity_] = std::move(item);
        ++count_;

        lock.unlock();
        not_empty_.notify_all();
    }

    T pop() {
        std::unique_lock<std::mutex> lock(mutex_);
        not_empty_.wait(lock, [this] { return count_ > 0; });

        T item = std::move(buffer_[head_]);
        head_ = (head_ + 1) % capacity_;
        --count_;

        lock.unlock();
        not_full_.notify_all();
        return item;
    }

private:
    std::unique_ptr<T[]> buffer_;  // 内存管理核心
    size_t head_ = 0;
    size_t count_ = 0;
    const size_t capacity_;
    std::mutex mutex_;
    std::condition_variable not_full_;
    std::condition_variable not_empty_;
};

最佳实践

  • 智能指针选择std::unique_ptr独占所有权,比shared_ptr性能更高
  • 索引计算(head_ + count_) % capacity_避免索引越界
  • 锁粒度:在notify前解锁减少临界区时间
  • 虚假唤醒防护:条件变量必须使用lambda谓词二次检查

常见错误

  • 循环引用:若缓冲区存储shared_ptr且对象持有缓冲区引用,需用weak_ptr打破循环
  • 死锁风险notify时未释放锁导致线程竞争
  • 索引错误:未使用模运算导致head_/tail_超出边界
  • 拷贝问题:未禁用拷贝导致多个实例共享同一unique_ptr

扩展知识

  • 性能优化:无锁环形缓冲区(如原子操作+环形队列)
  • weak_ptr应用场景:当外部对象需要访问缓冲区时:
    class Processor {
    public:
        void setBuffer(std::weak_ptr<ThreadSafeRingBuffer<int>> buf) {
            buffer_weak_ = buf;  // 弱引用避免循环
        }
        void process() {
            if (auto buf = buffer_weak_.lock()) {
                int item = buf->pop();
                // ...
            }
        }
    private:
        std::weak_ptr<ThreadSafeRingBuffer<int>> buffer_weak_;
    };
  • 批量操作:扩展push_bulk()/pop_bulk()减少锁竞争
  • 移动语义push(T&&)避免不必要的拷贝