Maxbad`Blog

线程安全-队列

2021-03-06 · 3 min read
#pragma once
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <memory>

/*
*
 * 线程安全队列
 * T为队列元素类型
 * 因为有std::mutex和std::condition_variable类成员,所以此类不支持复制构造函数也不支持赋值操作符(=)
 *
 * 来源: https://blog.csdn.net/u011726005/article/details/82670730
 */
template<class T, class Container = std::queue<T>>
class ThreadSafeQueue {
public:
	ThreadSafeQueue() = default;

	// 将元素加入队列
	template <class Element>
	void Push(Element&& element) {
		std::lock_guard<std::mutex> lock(mutex_);
		queue_.push(std::forward<Element>(element));
		not_empty_cv_.notify_one();
	}

	// 从队列中弹出一个元素,如果队列为空就阻塞
	void WaitAndPop(T& t) {
		std::unique_lock<std::mutex> lock(mutex_);
		not_empty_cv_.wait(lock, [this]() {
			return !queue_.empty();
			});

		t = std::move(queue_.front());
		queue_.pop()
	}

	// 从队列中弹出一个元素,如果队列为空就阻塞
	std::shared_ptr<T> WaitAndPop() {
		std::unique_lock<std::mutex> lock(mutex_);
		not_empty_cv_.wait(lock, [this]() {
			return !queue_.empty();
			});

		std::shared_ptr<T> t_ptr = std::make_shared<T>(queue_.front());
		queue_.pop();

		return t_ptr;
	}

	// 从队列中弹出一个元素,如果队列为空返回false
	bool TryPop(T& t) {
		std::lock_guard<std::mutex> lock(mutex_);
		if (queue_.empty()) {
			return false;
		}

		t = std::move(queue_.front());
		queue_.pop();
		return true;
	}

	// 从队列中弹出一个元素,如果队列为空返回空指针
	std::shared_ptr<T> TryPop() {
		std::lock_guard<std::mutex> lock(mutex_);
		if (queue_.empty()) {
			return std::shared_ptr<T>();
		}

		t = std::move(queue_.front());
		std::shared_ptr<T> t_ptr = std::make_shared<T>(queue_.front());
		queue_.pop();

		return t_ptr;
	}

	// 返回队列是否为空
	bool IsEmpty() const {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.empty();
	}

	// 返回队列中元素数个
	size_t size() {
		std::lock_guard<std::mutex> lock(mutex_);
		return queue_.size();
	}

private:
	ThreadSafeQueue(const ThreadSafeQueue&) = delete;
	ThreadSafeQueue& operator=(const ThreadSafeQueue&) = delete;
	ThreadSafeQueue(ThreadSafeQueue&&) = delete;
	ThreadSafeQueue& operator=(ThreadSafeQueue&&) = delete;

private:
	Container queue_;

	std::condition_variable not_empty_cv_;
	mutable std::mutex mutex_;
};