队列在线程间传递数据,是一个实际开发很常见的场景。做的好的话,同步可以被限制在队列本身,大大减少了同步问题和竞争条件。下面我们来抽象提取一个泛型的线程安全队列.
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>
template<typename T>
class threadsafe_queue
{
public:
threadsafe_queue(){}
threadsafe_queue(const threadsafe_queue& other)
{
std::lock_guard<std::mutex> lk(other.mut);
datat_queue = other.data_queue;
}
threadsafe_queue& operator=(const threadsafe_queue&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value);
data_cond.notify_one();
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty())
return false;
value = data_queue.front();
data_queue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty())
return null;
std::shared_ptr<T> res (std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();});
value = data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();});
std::shared_ptr<T> res(std::make_shared<T> data_queue.front()));
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
private:
mutable std::mutex mut; ①
std::queue<T> data_queue;
std::condition_variable data_cond;
};
threadsafe_queue<data_chunk> data_queue;
void data_prepare_thread()
{
while(more_data_to_prepare())
{
data_chunk const data = prepare_data();
data_queue.push(data);
}
}
void data_processing_thread()
{
data_chunk data;
data_queue.wait_and_pop(data);
process(data);
if(is_last_chunk(data))
break;
}
① mutable std::mutex mut; 中的mutable是为了突破const的限制,因为互斥元mut如果不用mutable修饰,在const函数中是不能进行非const引用的