功能需求描述
- 多线程向队列push数据时加锁
- 多线程队列pop数据时枷锁
- 队列为空时,pop阻塞等待
代码实现
//
// Created by bgape on 2024/9/4.
//
#ifndef THREADQUEUE_THREADQUEUE_HPP
#define THREADQUEUE_THREADQUEUE_HPP
#include <queue>
#include <mutex>
#include <condition_variable>
template<typename T>
class ThreadQueue {
private:
std::queue<T>* _queue;
mutable std::mutex _lock;
std::condition_variable _cv;
public:
ThreadQueue() {
_queue = new std::queue<T>;
}
~ThreadQueue() {
if (_queue != nullptr) {
delete _queue;
_queue = nullptr;
}
}
int push(T val){
std::unique_lock<std::mutex> lock(_lock);
_queue->push(val);
_cv.notify_one();
return 0;
}
T pop(){
std::unique_lock<std::mutex> lock(_lock);
_cv.wait(lock, [this]{return !_queue->empty();});
T val = _queue->front();
_queue->pop();
return val;
}
bool empty() const{
std::unique_lock<std::mutex> lock(_lock);
return _queue->empty();
}
int size() const{
std::unique_lock<std::mutex> lock(_lock);
return _queue->size();
}
};
#endif //THREADQUEUE_THREADQUEUE_HPP
这里的代码实现统一放在了一个hpp文件中实现。如果想分层h和cpp文件实现,需要考虑模板的显示实例化。这玩意挺搞人的,在写模板类的时候,尽量把实现和定义写在一个文件中吧。C++模板之隐式实例化、显示实例化、隐式调用、显示调用和模板特化详解
注意: std::mutex
和std::condition_variable
不支持拷贝构造函数和赋值运算符重载函数,而默认拷贝构造函数默认行为会调用成员变量的拷贝构造函数进行构造,因此这里的ThreadQueue类也时不支持拷贝构造函数的。默认情况下,ThreadQueue也不应该支持拷贝构造函数,示例代码里可以考虑显示的删除拷贝构造函数。当然,如果有特殊需要也可以自己实现拷贝构造函数的。这里提这一点,主要是提醒在ThreadQueue实例化变量做函数参数时,不要使用值传递
测试代码
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include "ThreadQueue.hpp"
void producer(ThreadQueue<std::string>& Q) {
for (int i=0;i<10;i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
Q.push("This is item:" + std::to_string(i));
}
}
void consumer(ThreadQueue<std::string>& Q) {
int n = 0;
while (n<10) {
std::cout << "Get --- " << Q.pop() << std::endl;
n++;
}
}
int main() {
ThreadQueue<std::string> Q;
std::thread pt(producer, std::ref(Q));
std::thread ct(consumer, std::ref(Q));
pt.join();
ct.join();
return 0;
}
注意: 使用引用避免值传递带来的拷贝。