线程安全队列(使用互斥锁进行实现)
线程安全队列(使用互斥锁进行实现)
没有设置队列上限的线程安全队列
只需要采取一个std::condition_variable变量,用于处理队列为空的情况
以下是示例代码,涉及了std::mutex和std::condition_variable、std::unique_lock、std::lockguard等多线程交互的类。
测试方式采取的是3个生成者和一个消费者,消费者监测生产者push的数据是否有异常,同时拿一个线程在十秒后调用Finish()函数。
示例1:没有设置队列上限的线程安全队列(包含测试代码)
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <atomic>
#include <functional>
#include <string>
#include <chrono>
#include <map>
template <typename T>
class ThreadSafetyQueue
{
public:
ThreadSafetyQueue() : finish_(false) {}
bool push(T &data)
{
std::unique_lock<std::mutex> lock(mtx_);
if(finish_)
{
std::cout << "queue finish" << std::endl;
return false;
}
data_queue_.push(data);
lock.unlock(); // 注意:解锁必须在通知之前
cv_.notify_one();
return true;
}
bool pop(T &data)
{
std::unique_lock<std::mutex> lock(mtx_);
while(!finish_ && data_queue_.empty()) // 防止假醒
{
cv_.wait(lock);
}
if(finish_)
{
std::cout << "queue finish" << std::endl;
return false;
}
data = data_queue_.front();
data_queue_.pop();
return true;
}
bool empty()
{
std::unique_lock<std::mutex> lock(mtx_);
if(data_queue_.empty())
{
return true;
}
return false;
}
int size()
{
std::unique_lock<std::mutex> lock(mtx_);
return data_queue_.size();
}
void Finish()
{
finish_ = true;
cv_.notify_all();
}
private:
std::mutex mtx_;
std::queue<T> data_queue_;
std::condition_variable cv_;
std::atomic_bool finish_;
};
struct test_data
{
int num;
std::string str;
};
int main()
{
ThreadSafetyQueue<test_data> queue;
std::function<void(std::string)> product_func = ([&queue](std::string name){
for(int i = 0; i < 1000000; ++i)
{
test_data td{i, name};
queue.push(td);
}
});
std::function<void(void)> consumer_func = ([&queue](){
std::map<std::string, int> test_mp;
while(1)
{
test_data data;
if(queue.pop(data))
{
if(test_mp.find(data.str) == test_mp.end())
{
test_mp[data.str] = 0;
std::cout << "add consumer name is: " << data.str << std::endl;
}
if(test_mp[data.str] == data.num)
{
test_mp[data.str] ++;
}
else
{
std::cout << "error" << std::endl;
std::cout << "consumer name is: " << data.str << std::endl;
std::cout << "consumer " << data.num << std::endl;
}
}
}
});
std::function<void(void)> finish_func = ([&queue](){
std::this_thread::sleep_for(std::chrono::seconds(10));
queue.Finish();
});
std::thread producer1(product_func, "producer1");
std::thread producer2(product_func, "producer2");
std::thread producer3(product_func, "producer3");
std::thread consumer1(consumer_func);
std::thread finish_thread(finish_func);
while (1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
queue.Finish();
producer1.join();
producer2.join();
producer3.join();
consumer1.join();
finish_thread.join();
return 0;
}
设置队列上限的线程安全队列
需要两个std::condition_variable变量,用于处理队列为空和队列为满的情况。
增加了设置MaxSize的函数。
示例中,size=0表示队列没有上限。
示例2:设置队列上限的线程安全队列(包含测试代码)
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <atomic>
#include <functional>
#include <string>
#include <chrono>
#include <map>
template <typename T>
class ThreadSafetyQueue
{
public:
ThreadSafetyQueue(size_t size = 0) :
finish_{false},
max_size_{size}
{
}
bool push(T &data)
{
std::unique_lock<std::mutex> lock(mtx_);
while (CheckFull() && !finish_)
{
// std::cout << "queue full" << std::endl;
full_cv_.wait(lock);
}
if(finish_)
{
// std::cout << "queue finish" << std::endl;
return false;
}
data_queue_.push(data);
lock.unlock(); // 解锁在notify_one之前更合适
empty_cv_.notify_one();
return true;
}
bool pop(T &data)
{
std::unique_lock<std::mutex> lock(mtx_);
while(!finish_ && data_queue_.empty()) // 防止假醒
{
empty_cv_.wait(lock);
}
if(finish_)
{
// std::cout << "queue finish" << std::endl;
return false;
}
data = data_queue_.front();
data_queue_.pop();
full_cv_.notify_one();
return true;
}
bool empty()
{
std::unique_lock<std::mutex> lock(mtx_);
if(data_queue_.empty())
{
return true;
}
return false;
}
bool full()
{
std::unique_lock<std::mutex> lock(mtx_);
if(data_queue_.size() >= max_size_)
{
return true;
}
return false;
}
int size()
{
std::unique_lock<std::mutex> lock(mtx_);
return data_queue_.size();
}
void Finish()
{
finish_ = true;
full_cv_.notify_all();
empty_cv_.notify_all();
}
void SetMaxSize(size_t size)
{
std::unique_lock<std::mutex> lock(mtx_);
max_size_ = size;
lock.unlock();
full_cv_.notify_all();
}
private:
std::mutex mtx_;
std::queue<T> data_queue_;
std::condition_variable full_cv_;
std::condition_variable empty_cv_;
volatile size_t max_size_;
std::atomic_bool finish_;
bool CheckFull()
{
if(max_size_ == 0)
return false;
else
return data_queue_.size() >= max_size_;
}
};
struct test_data
{
int num;
std::string str;
};
int main()
{
ThreadSafetyQueue<test_data> queue(1000);
std::function<void(std::string)> product_func = ([&queue](std::string name){
for(int i = 0; i < 1000000; ++i)
{
test_data td{i, name};
queue.push(td);
}
});
std::function<void(void)> consumer_func = ([&queue](){
std::map<std::string, int> test_mp;
while(1)
{
test_data data;
if(queue.pop(data))
{
if(test_mp.find(data.str) == test_mp.end())
{
test_mp[data.str] = 0;
std::cout << "add consumer name is: " << data.str << std::endl;
}
if(test_mp[data.str] == data.num)
{
test_mp[data.str] ++;
}
else
{
std::cout << "error" << std::endl;
std::cout << "consumer name is: " << data.str << std::endl;
std::cout << "consumer " << data.num << std::endl;
}
}
}
});
std::function<void(void)> finish_func = ([&queue](){
std::this_thread::sleep_for(std::chrono::seconds(10));
queue.Finish();
});
std::thread producer1(product_func, "producer1");
std::thread producer2(product_func, "producer2");
std::thread producer3(product_func, "producer3");
std::thread consumer1(consumer_func);
std::thread finish_thread(finish_func);
while (1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
queue.Finish();
producer1.join();
producer2.join();
producer3.join();
consumer1.join();
finish_thread.join();
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步