目錄
- 簡介
- 執行緒安全佇列
簡介
記錄開發時自用的小輪子:執行緒安全佇列
執行緒安全佇列
#ifndef THREADSAFEQUEUE_H
#define THREADSAFEQUEUE_H
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <memory>
template<typename T>
class ThreadSafeQueue
{
public:
ThreadSafeQueue();
ThreadSafeQueue(const ThreadSafeQueue& other);
ThreadSafeQueue& operator=(const ThreadSafeQueue& other);
~ThreadSafeQueue();
public:
void push(T new_value);
//對於pop方法,std::queue中的pop只負責彈出元素,不返回元素
//這裡為了介面簡化,設計為在pop的同時返回彈出的元素
//timeout為超時時間,單位為毫秒
//預設阻塞pop
bool wait_and_pop(T& value, std::chrono::milliseconds timeout_millisecond = std::chrono::milliseconds::max());
std::shared_ptr<T> wait_and_pop(std::chrono::milliseconds timeout_millisecond = std::chrono::milliseconds::max());
bool empty() const;
size_t size() const;
T& front();
const T& front() const;
std::shared_ptr<T> front_ptr();
private:
mutable std::mutex mtx;
std::queue<T> data_queue;
std::condition_variable data_cond;
};
template<typename T>
ThreadSafeQueue<T>::ThreadSafeQueue()
{
}
template<typename T>
ThreadSafeQueue<T>::ThreadSafeQueue(const ThreadSafeQueue& other)
{
std::lock_guard<std::mutex> lock(other.mtx);
data_queue = other.data_queue;
}
template<typename T>
ThreadSafeQueue<T>& ThreadSafeQueue<T>::operator=(const ThreadSafeQueue& other)
{
if (this == &other)
{
return *this;
}
std::lock(mtx, other.mtx);
std::lock_guard<std::mutex> self_lock(mtx, std::adopt_lock);
std::lock_guard<std::mutex> other_lock(other.mtx, std::adopt_lock);
data_queue = other.data_queue;
return *this;
}
template<typename T>
ThreadSafeQueue<T>::~ThreadSafeQueue()
{
}
template<typename T>
void ThreadSafeQueue<T>::push(T new_value)
{
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(std::move(new_value));
data_cond.notify_one();
}
template<typename T>
bool ThreadSafeQueue<T>::wait_and_pop(T& value, std::chrono::milliseconds timeout_millisecond)
{
std::unique_lock<std::mutex> lock(mtx);
if (data_queue.empty())
{
if (timeout_millisecond == std::chrono::milliseconds::max())
{
data_cond.wait(lock, [this] {return !data_queue.empty();});
}
else
{
if (!data_cond.wait_for(lock, timeout_millisecond, [this] {return !data_queue.empty();}))
return false;
}
}
value = std::move(data_queue.front());
data_queue.pop();
return true;
}
template<typename T>
std::shared_ptr<T> ThreadSafeQueue<T>::wait_and_pop(std::chrono::milliseconds timeout_millisecond)
{
std::unique_lock<std::mutex> lock(mtx);
if (data_queue.empty())
{
if (timeout_millisecond == std::chrono::milliseconds::max())
{
data_cond.wait(lock, [this] {return !data_queue.empty();});
}
else
{
if (!(data_cond.wait_for(lock, timeout_millisecond, [this] {return !data_queue.empty();})))
return std::shared_ptr<T>();
}
}
std::shared_ptr<T> res(std::make_shared<T>(std::move(data_queue.front())));
data_queue.pop();
return res;
}
template<typename T>
bool ThreadSafeQueue<T>::empty() const
{
std::lock_guard<std::mutex> lock(mtx);
return data_queue.empty();
}
template<typename T>
size_t ThreadSafeQueue<T>::size() const
{
std::lock_guard<std::mutex> lock(mtx);
return data_queue.size();
}
template<typename T>
T& ThreadSafeQueue<T>::front()
{
std::lock_guard<std::mutex> lock(mtx);
if(data_queue.empty())
throw std::runtime_error("queue is empty");
return data_queue.front();
}
template<typename T>
const T& ThreadSafeQueue<T>::front() const
{
std::lock_guard<std::mutex> lock(mtx);
if(data_queue.empty())
throw std::runtime_error("queue is empty");
return data_queue.front();
}
template<typename T>
std::shared_ptr<T> ThreadSafeQueue<T>::front_ptr()
{
std::lock_guard<std::mutex> lock(mtx);
if(data_queue.empty())
return std::shared_ptr<T>();
return std::make_shared<T>(data_queue.front());
}
#endif // THREADSAFEQUEUE_H