多线程安全的queue类

文章展示了如何基于《C++并发编程实战(第二版)》中的代码实现一个线程安全的队列`threadsafe_queue`,该队列使用了内置的队列、互斥锁和条件变量来保证并发环境下的正确性。队列提供了`push`、`pop`、`front`等操作,并处理了空队列的情况。此外,还提供了交换和等于操作的实现。

声明:本文参考自《C++并发编程实战(第二版)》

       本文试图根据书中的代码在力所能及范围内实现一个queue类,虽然底层用了现成的queue,比较丑陋(请忽略)



struct empty_queue :std::exception
{
	const char ch = 'n';
	const char* what() const throw() { return &ch; }
};
template<class T>
class threadsafe_queue;
template<class T>
void swap(threadsafe_queue<T>& l, threadsafe_queue<T>& r);
template<class T>
bool operator==(threadsafe_queue<T>&, threadsafe_queue<T>&);
template<class T>
class threadsafe_queue
{
private:
	queue<T>data;
	mutable std::mutex mut;
	mutable std::shared_mutex smut;
	std::condition_variable dc;
public:
	threadsafe_queue() = default;
	threadsafe_queue(const threadsafe_queue& other)
	{
		std::lock_guard<std::mutex>lck(other.mut);
		data = other.data;
	}
	std::mutex& get_mutex()
	{
		return this->mut;
	}
	queue<T>& get_data()
	{
		return this->data;
	}
/*
	_NODISCARD unsigned int size()
	{
		lock_guard<std::mutex>lck(mut);
		return data.size();
	}
*/
	T front()
	{
		std::lock_guard<std::shared_mutex>lck(smut);
		if (data.empty())
			throw empty_queue();
		return data.front();
	}
	std::shared_ptr<T>front(T)
	{
		std::lock_guard<std::shared_mutex>lck(smut);
		if (data.empty())
			throw empty_queue();
		const std::shared_ptr<T>res(std::make_shared<T>(data.front()));
		return res;
	}
	void push(const T& value)
	{
		std::lock_guard<std::mutex>lck(mut);
		data.push(value);
		dc.notify_one();
	}
	void push(T&& value)
	{
		std::lock_guard<std::mutex>lck(mut);
		data.push(std::move(value));
		dc.notify_one();
	}
	std::shared_ptr<T>pop()
	{
		std::lock_guard<std::mutex>lck(mut);
		if (data.empty())
			throw empty_queue();
		const std::shared_ptr<T> res(std::make_shared<T>(data.front()));
		data.pop();
		return res;
	}
	void pop(T& value)
	{
		std::lock_guard<std::mutex>lck(mut);
		if (data.empty())
			throw empty_queue();
		value = data.front();
		data.pop();
	}
	void wait_and_pop(T& value)
	{
		std::unique_lock<std::mutex>lck(mut);
		dc.wait(lck, [this] {return !data.empty(); });
		value = data.front();
		data.pop();
	}
	std::shared_ptr<T>wait_and_pop()
	{
		std::unique_lock<std::mutex>lck(mut);
		dc.wait(lck, [this] {return !data.empty(); });
		std::shared_ptr<T>res(std::make_shared<T>(data.front()));
		data.pop();
		return res;
	}
	bool try_pop(T& value)
	{
		std::lock_guard<std::mutex>lk(mut);
		if (!data.empty())
			return false;
		value = data.front();
		data.pop();
		return true;
	}
	std::shared_ptr<T>try_pop()
	{
		std::lock_guard<std::mutex>lck(mut);
		if (data.empty())
			return std::shared_ptr<T>();
		std::shared_ptr<T>res(std::make_shared<T>(data.front()));
		data.pop();
		return res;
	}
	bool empty()const
	{
		std::lock_guard<std::mutex>lck(mut);
		return data.empty();
	}
	void swap(threadsafe_queue<T>& other) noexcept
	{
		// c++11 or c++14
		//lock(this->m, other.m);
		//std::lock_guard<std::mutex>lck1(other.m, std::adopt_lock);
		//std::lock_guard<std::mutex>lck2(this->m, std::adopt_lock);

		// c++17
		std::scoped_lock guard(this->mut, other.mut);

		this->data.swap(other.data);
	}
	friend void swap(threadsafe_queue<T>& l, threadsafe_queue<T>& r)
	{
		// c++11 or c++14
		//std::lock(l.get_mutex(), r.get_mutex());
		//std::lock_guard<std::mutex>lck1(l.get_mutex(), std::adopt_lock);
		//std::lock_guard<std::mutex>lck2(l.get_mutex(), std::adopt_lock);

		// c++17
		std::scoped_lock guard(l.get_mutex(), r.get_mutex());
		std::swap(l.get_data(), r.get_data());
	}
	bool operator==(const threadsafe_queue<T>& oth)
	{
		// c++11 or c++14
		//std::lock(l.get_mutex(), r.get_mutex());
		//std::lock_guard<std::mutex>lck1(l.get_mutex(), std::adopt_lock);
		//std::lock_guard<std::mutex>lck2(l.get_mutex(), std::adopt_lock);

		// c++17
		std::scoped_lock guard(mut, oth.mut);
		return data == oth.data;
	}
	friend bool operator==(threadsafe_queue<T>& l, threadsafe_queue<T>& r)
	{
		// c++11 or c++14
		//std::lock(l.get_mutex(), r.get_mutex());
		//std::lock_guard<std::mutex>lck1(l.get_mutex(), std::adopt_lock);
		//std::lock_guard<std::mutex>lck2(l.get_mutex(), std::adopt_lock);

		// c++17
		std::scoped_lock guard(l.get_mutex(), r.get_mutex());
		return l.get_data() == r.get_data();
	}
};


测试代码如下:

void oper(threadsafe_queue<int>& s)
{
	for (int i = 0; i < 100; i++)
	{
		s.push(i);
		cout << "push : " << i << endl;
	}
	for (int i = 0; i < 50; i++)
	{
		shared_ptr<int> ptr = s.pop();
		cout << "pop : " << *ptr << endl;
	}
	for (int i = 0; i < 25; i++)
	{
		int j = 0;
		s.wait_and_pop(j);
		cout << "wait_and_pop : " << j << endl;
	}
	for (int i = 0; i < 25; i++)
	{
		shared_ptr<int> g_res = s.wait_and_pop();
		cout << "s_wait_and_pop : " << *g_res << endl;
	}
	if (s.empty())
		cout << "empty" << endl;
}
int main()
{
	threadsafe_queue<int>s1;
	threadsafe_queue<int>s2;
	thread obj1(oper, ref(s1));
	thread obj2(oper, ref(s2));
	obj1.join();
	obj2.join();
	threadsafe_queue<int> s3(s2);
	thread obj3(oper, ref(s3));
	obj3.join();

	threadsafe_queue<int>s4;
	for (int i = 0; i < 5; i++)
		s4.push(i);
	threadsafe_queue<int>s5;
	for (int i = 5; i < 10; i++)
		s5.push(i);

	swap(s4, s5);
	while (!s4.empty())
	{
		int i = 0;
		int tmp = s4.front();
		cout << tmp << " ";
		s4.pop(i);
		cout << i << " " << endl;
	}

	s4.swap(s5);
	while (!s4.empty())
	{
		int i = 0;
		shared_ptr<int>tmp = s4.front(i);
		cout << *tmp << " ";
		s4.pop(i);
		cout << i << " " << endl;
	}

	threadsafe_queue<int>s6;
	for (int i = 0; i < 5; i++)
		s6.push(i);
	threadsafe_queue<int>s7;
	for (int i = 0; i < 5; i++)
		s7.push(i);
	bool flg1 = (s6 == s7);
	bool flg2 = s6.operator==(s7);
	cout << flg1 << " " << flg2 << endl;

	threadsafe_queue<int>s8;
	for (int i = 0; i < 15; i++)
		s8.push(i);
	for (int i = 0; i < 5; i++)
	{
		int t = 0;
		bool res = s8.try_pop(t);
		if (res)
			cout << t << endl;
		else
			cout << "empty" << endl;
	}
	for (int i = 0; i < 5; i++)
	{
		shared_ptr<int>g_res = s8.try_pop();
		cout << *g_res << endl;
	}
	return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值