DoubleQueue.hpp 7.5 KB
Newer Older
独孤过's avatar
独孤过 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
* 文件名称:DoubleQueue.hpp
* 语言标准:C++17
* 
* 创建日期:2019年03月08日
* 更新日期:2023年01月07日
* 
* 摘要
* 1.定义双缓冲队列类模板DoubleQueue。
* 2.包含入口队列和出口队列。在放入元素之时,只锁定入口互斥元;在取出元素之时,先锁定出口互斥元,若出口队列为空,再锁定入口互斥元,并且交换两个队列。
*   以此降低两个队列的相互影响,从而提高出入队列的效率。
* 3.支持自定义队列容量和动态调整容量,支持批量出入队列和清空队列。
* 
* 作者:许聪
* 邮箱:solifree@qq.com
* 
* 版本:v2.0.0
* 变化
* v2.0.0
* 1.更名Queue为DoubleQueue。
* 2.定制复制语义和移动语义。
*/

#pragma once

#include <optional>
独孤过's avatar
独孤过 已提交
27
#include <utility>
独孤过's avatar
独孤过 已提交
28 29 30 31
#include <list>
#include <atomic>
#include <mutex>

独孤过's avatar
独孤过 已提交
32
#include "Common.hpp"
独孤过's avatar
独孤过 已提交
33 34 35

ETERFREE_SPACE_BEGIN

独孤过's avatar
独孤过 已提交
36
template <typename _Element>
独孤过's avatar
独孤过 已提交
37
class DoubleQueue final
独孤过's avatar
独孤过 已提交
38 39
{
public:
独孤过's avatar
独孤过 已提交
40 41
	using Element = _Element;
	using QueueType = std::list<Element>;
独孤过's avatar
独孤过 已提交
42 43 44 45
	using SizeType = typename QueueType::size_type;
	using MutexType = std::mutex;

private:
独孤过's avatar
独孤过 已提交
46
	using Atomic = std::atomic<SizeType>;
独孤过's avatar
独孤过 已提交
47 48

private:
独孤过's avatar
独孤过 已提交
49 50
	Atomic _capacity;
	Atomic _size;
独孤过's avatar
独孤过 已提交
51 52 53 54 55 56 57 58

	mutable MutexType _entryMutex;
	QueueType _entryQueue;

	mutable MutexType _exitMutex;
	QueueType _exitQueue;

private:
独孤过's avatar
独孤过 已提交
59
	static auto get(const Atomic& _atomic) noexcept
独孤过's avatar
独孤过 已提交
60 61 62 63
	{
		return _atomic.load(std::memory_order_relaxed);
	}

独孤过's avatar
独孤过 已提交
64
	static void set(Atomic& _atomic, SizeType _size) noexcept
独孤过's avatar
独孤过 已提交
65 66 67 68
	{
		_atomic.store(_size, std::memory_order_relaxed);
	}

独孤过's avatar
独孤过 已提交
69
	static auto exchange(Atomic& _atomic, SizeType _size) noexcept
独孤过's avatar
独孤过 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	{
		return _atomic.exchange(_size, std::memory_order_relaxed);
	}

	static void copy(DoubleQueue& _left, const DoubleQueue& _right);

	static void move(DoubleQueue& _left, DoubleQueue&& _right) noexcept;

private:
	auto add(SizeType _size) noexcept
	{
		return this->_size.fetch_add(_size, \
			std::memory_order_relaxed);
	}

	auto subtract(SizeType _size) noexcept
	{
		return this->_size.fetch_sub(_size, \
			std::memory_order_relaxed);
	}

独孤过's avatar
独孤过 已提交
91 92
	bool valid(QueueType& _queue) const noexcept;

独孤过's avatar
独孤过 已提交
93 94 95 96 97 98 99 100 101
public:
	// 若_capacity小于等于零,则无限制,否则其为上限值
	DoubleQueue(SizeType _capacity = 0) : \
		_capacity(_capacity), _size(0) {}

	DoubleQueue(const DoubleQueue& _another);

	DoubleQueue(DoubleQueue&& _another);

独孤过's avatar
独孤过 已提交
102
	DoubleQueue& operator=(const DoubleQueue& _doubleQueue);
独孤过's avatar
独孤过 已提交
103

独孤过's avatar
独孤过 已提交
104
	DoubleQueue& operator=(DoubleQueue&& _doubleQueue);
独孤过's avatar
独孤过 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

	auto capacity() const noexcept
	{
		return get(_capacity);
	}

	void reserve(SizeType _capacity) noexcept
	{
		set(this->_capacity, _capacity);
	}

	auto size() const noexcept { return get(_size); }
	bool empty() const noexcept { return size() == 0; }

	DEPRECATED
	auto& mutex() noexcept { return _exitMutex; }

独孤过's avatar
独孤过 已提交
122 123
	std::optional<SizeType> push(const Element& _element);
	std::optional<SizeType> push(Element&& _element);
独孤过's avatar
独孤过 已提交
124 125 126 127

	std::optional<SizeType> push(QueueType& _queue);
	std::optional<SizeType> push(QueueType&& _queue);

独孤过's avatar
独孤过 已提交
128 129
	bool pop(Element& _element);
	std::optional<Element> pop();
独孤过's avatar
独孤过 已提交
130 131 132 133 134 135

	bool pop(QueueType& _queue);

	SizeType clear();
};

独孤过's avatar
独孤过 已提交
136 137
template <typename _Element>
void DoubleQueue<_Element>::copy(DoubleQueue& _left, \
独孤过's avatar
独孤过 已提交
138 139 140 141 142 143 144 145
	const DoubleQueue& _right)
{
	_left._exitQueue = _right._exitQueue;
	_left._entryQueue = _right._entryQueue;
	set(_left._size, get(_right._size));
	set(_left._capacity, get(_right._capacity));
}

独孤过's avatar
独孤过 已提交
146 147
template <typename _Element>
void DoubleQueue<_Element>::move(DoubleQueue& _left, \
独孤过's avatar
独孤过 已提交
148 149 150 151 152 153 154 155
	DoubleQueue&& _right) noexcept
{
	_left._exitQueue = std::move(_right._exitQueue);
	_left._entryQueue = std::move(_right._entryQueue);
	set(_left._size, exchange(_right._size, 0));
	set(_left._capacity, exchange(_right._capacity, 0));
}

独孤过's avatar
独孤过 已提交
156 157 158 159 160 161 162 163 164 165
template <typename _Element>
bool DoubleQueue<_Element>::valid(QueueType& _queue) const noexcept
{
	auto capacity = this->capacity();
	if (capacity <= 0) return true;

	auto size = this->size();
	return size < capacity && _queue.size() <= capacity - size;
}

独孤过's avatar
独孤过 已提交
166 167
template <typename _Element>
DoubleQueue<_Element>::DoubleQueue(const DoubleQueue& _another)
独孤过's avatar
独孤过 已提交
168
{
独孤过's avatar
独孤过 已提交
169 170
	std::scoped_lock lock(_another._exitMutex, \
		_another._entryMutex);
独孤过's avatar
独孤过 已提交
171 172 173
	copy(*this, _another);
}

独孤过's avatar
独孤过 已提交
174 175
template <typename _Element>
DoubleQueue<_Element>::DoubleQueue(DoubleQueue&& _another)
独孤过's avatar
独孤过 已提交
176
{
独孤过's avatar
独孤过 已提交
177 178
	std::scoped_lock lock(_another._exitMutex, \
		_another._entryMutex);
独孤过's avatar
独孤过 已提交
179 180 181
	move(*this, std::forward<DoubleQueue>(_another));
}

独孤过's avatar
独孤过 已提交
182
template <typename _Element>
独孤过's avatar
独孤过 已提交
183
auto DoubleQueue<_Element>::operator=(const DoubleQueue& _doubleQueue) \
独孤过's avatar
独孤过 已提交
184 185
-> DoubleQueue&
{
独孤过's avatar
独孤过 已提交
186
	if (&_doubleQueue != this)
独孤过's avatar
独孤过 已提交
187 188
	{
		std::scoped_lock lock(this->_exitMutex, this->_entryMutex, \
独孤过's avatar
独孤过 已提交
189 190
			_doubleQueue._exitMutex, _doubleQueue._entryMutex);
		copy(*this, _doubleQueue);
独孤过's avatar
独孤过 已提交
191 192 193 194
	}
	return *this;
}

独孤过's avatar
独孤过 已提交
195
template <typename _Element>
独孤过's avatar
独孤过 已提交
196
auto DoubleQueue<_Element>::operator=(DoubleQueue&& _doubleQueue) \
独孤过's avatar
独孤过 已提交
197 198
-> DoubleQueue&
{
独孤过's avatar
独孤过 已提交
199
	if (&_doubleQueue != this)
独孤过's avatar
独孤过 已提交
200 201
	{
		std::scoped_lock lock(this->_exitMutex, this->_entryMutex, \
独孤过's avatar
独孤过 已提交
202 203
			_doubleQueue._exitMutex, _doubleQueue._entryMutex);
		move(*this, std::forward<DoubleQueue>(_doubleQueue));
独孤过's avatar
独孤过 已提交
204 205 206 207
	}
	return *this;
}

独孤过's avatar
独孤过 已提交
208 209
template <typename _Element>
auto DoubleQueue<_Element>::push(const Element& _element) \
独孤过's avatar
独孤过 已提交
210 211 212 213 214 215 216 217 218 219 220
-> std::optional<SizeType>
{
	std::lock_guard lock(_entryMutex);
	if (auto capacity = this->capacity(); \
		capacity > 0 && size() >= capacity)
		return std::nullopt;

	_entryQueue.push_back(_element);
	return add(1);
}

独孤过's avatar
独孤过 已提交
221 222
template <typename _Element>
auto DoubleQueue<_Element>::push(Element&& _element) \
独孤过's avatar
独孤过 已提交
223 224 225 226 227 228 229
-> std::optional<SizeType>
{
	std::lock_guard lock(_entryMutex);
	if (auto capacity = this->capacity(); \
		capacity > 0 && size() >= capacity)
		return std::nullopt;

独孤过's avatar
独孤过 已提交
230
	_entryQueue.push_back(std::forward<Element>(_element));
独孤过's avatar
独孤过 已提交
231 232 233
	return add(1);
}

独孤过's avatar
独孤过 已提交
234 235
template <typename _Element>
auto DoubleQueue<_Element>::push(QueueType& _queue) \
独孤过's avatar
独孤过 已提交
236 237 238
-> std::optional<SizeType>
{
	std::lock_guard lock(_entryMutex);
独孤过's avatar
独孤过 已提交
239
	if (not valid(_queue)) return std::nullopt;
独孤过's avatar
独孤过 已提交
240 241 242 243 244 245

	auto size = _queue.size();
	_entryQueue.splice(_entryQueue.cend(), _queue);
	return add(size);
}

独孤过's avatar
独孤过 已提交
246 247
template <typename _Element>
auto DoubleQueue<_Element>::push(QueueType&& _queue) \
独孤过's avatar
独孤过 已提交
248 249 250
-> std::optional<SizeType>
{
	std::lock_guard lock(_entryMutex);
独孤过's avatar
独孤过 已提交
251
	if (not valid(_queue)) return std::nullopt;
独孤过's avatar
独孤过 已提交
252 253 254 255 256 257 258 259

	auto size = _queue.size();
	_entryQueue.splice(_entryQueue.cend(), \
		std::forward<QueueType>(_queue));
	return add(size);
}

// 支持元素的完全移动语义
独孤过's avatar
独孤过 已提交
260 261
template <typename _Element>
bool DoubleQueue<_Element>::pop(Element& _element)
独孤过's avatar
独孤过 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
{
	std::lock_guard lock(_exitMutex);
	if (empty()) return false;

	if (_exitQueue.empty())
	{
		std::lock_guard lock(_entryMutex);
		_exitQueue.swap(_entryQueue);
	}

	subtract(1);
	_element = std::move(_exitQueue.front());
	_exitQueue.pop_front();
	return true;
}

// 编译器RVO机制决定完全移动语义或者移动语义与复制语义
独孤过's avatar
独孤过 已提交
279 280
template <typename _Element>
auto DoubleQueue<_Element>::pop() -> std::optional<Element>
独孤过's avatar
独孤过 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
{
	std::lock_guard lock(_exitMutex);
	if (empty()) return std::nullopt;

	if (_exitQueue.empty())
	{
		std::lock_guard lock(_entryMutex);
		_exitQueue.swap(_entryQueue);
	}

	subtract(1);
	std::optional result = std::move(_exitQueue.front());
	_exitQueue.pop_front();
	return result;
}

独孤过's avatar
独孤过 已提交
297 298
template <typename _Element>
bool DoubleQueue<_Element>::pop(QueueType& _queue)
独孤过's avatar
独孤过 已提交
299 300 301 302 303 304 305 306 307 308 309 310
{
	std::lock_guard exitLock(_exitMutex);
	if (empty()) return false;

	_queue.splice(_queue.cend(), _exitQueue);

	std::lock_guard entryLock(_entryMutex);
	_queue.splice(_queue.cend(), _entryQueue);
	set(_size, 0);
	return true;
}

独孤过's avatar
独孤过 已提交
311 312
template <typename _Element>
auto DoubleQueue<_Element>::clear() -> SizeType
独孤过's avatar
独孤过 已提交
313 314 315 316 317 318 319 320
{
	std::scoped_lock lock(_exitMutex, _entryMutex);
	_exitQueue.clear();
	_entryQueue.clear();
	return exchange(_size, 0);
}

ETERFREE_SPACE_END