题目
设计线程安全的环形缓冲区(Ring Buffer)类,使用智能指针管理内存,支持多生产者多消费者场景
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
智能指针内存管理, 多线程同步, 环形缓冲区设计, 循环引用避免, 异常安全
快速回答
实现要点:
- 使用
std::unique_ptr管理缓冲区内存,避免手动delete - 通过
std::mutex和std::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&&)避免不必要的拷贝