安全队列(SafeQueue)-多线程安全

原文转自:http://www.tanjp.com (即时修正和更新)

多线程安全的先进先出队列

 

多线程安全的队列,可支持临界条件的阻塞与非阻塞两种模式切换。可通过条件变量来挂起等待加入/取出,条件满足时又能即时唤醒加入/取出。

思路和想法都比较简单,就是一些应用的方法,就不多说了,直接看代码很好了解。

template
class SafeQueue
{
    	static const uint32 kDefaultMaxsize = 4294967290U; //容量上限
public:
    	explicit SafeQueue(bool pb_block = true, uint32 pn_maxsize = kDefaultMaxsize)
    		: mb_block(pb_block)
    		, mn_maxsize(pn_maxsize > 0 ? pn_maxsize : kDefaultMaxsize)
    		, mc_queue()
		, mb_push_waiting(0)
		, mb_pop_waiting(0) { }
	~SafeQueue() { }
	bool push(const tpType & po_val)
	{
		{
			std::lock_guard lock(mo_mutex);
			while ((mc_queue.size() >= mn_maxsize) && mb_block)
			{
				++mb_push_waiting;
				mo_cond_push.wait(mo_mutex);
				--mb_push_waiting;
			}
			if ((mc_queue.size() >= mn_maxsize) && (!mb_block))
			{
				return false;
			}
			mc_queue.push(po_val);
		} //锁已释放
		if (mb_pop_waiting > 0) { mo_cond_pop.notify_one(); }
		return true;
	}
	bool pop(tpType & po_val)
	{
		{
			std::lock_guard lock(mo_mutex);
			while (mc_queue.empty() && mb_block)
			{
				++mb_pop_waiting;
				mo_cond_pop.wait(mo_mutex);
				--mb_pop_waiting;
			}
			if (mc_queue.empty() && (!mb_block))
			{
				return false;
			}			
			po_val = std::move(mc_queue.front());
			mc_queue.pop();
		} //锁已释放

		if (mb_push_waiting > 0) { mo_cond_push.notify_one(); }		
		return true;
	}
	bool pop()
	{
		{
			std::lock_guard lock(mo_mutex);
			while (mc_queue.empty() && mb_block)
			{
				++mb_pop_waiting;
				mo_cond_pop.wait(mo_mutex);
				--mb_pop_waiting;
			}
			if (mc_queue.empty() && (!mb_block))
			{
				return false;
			}
			mc_queue.pop();
		}
		if (mb_push_waiting > 0) { mo_cond_push.notify_one(); }
		return true;
	}
	bool front(tpType & po_val)
	{
		std::lock_guard lock(mo_mutex);
		if (mc_queue.empty()) {	return false; }
		po_val = mc_queue.front();
		return true;
	}
	bool empty()
	{
		std::lock_guard lock(mo_mutex);
		return mc_queue.empty();
	}
	bool full()
	{
		std::lock_guard lock(mo_mutex);
		return (mc_queue.size() >= mn_maxsize);
	}
	uint32 size()
	{
		std::lock_guard lock(mo_mutex);
		return (uint32)mc_queue.size();
	}
	void clear()
	{
		{
			std::lock_guard lock(mo_mutex);
			while (!mc_queue.empty()) {	mc_queue.pop();	}
		}
		mo_cond_push.notify_all();
	}
	void set_block(bool pb_block)
	{
		{
			std::lock_guard lock(mo_mutex);
			if (mb_block == pb_block) {	return;	}
			mb_block = pb_block;
		}
		mo_cond_pop.notify_all();
		mo_cond_push.notify_all();
	}
	bool set_maxsize(uint32 pn_maxsize)
	{
		std::lock_guard lock(mo_mutex);
		if ((pn_maxsize < mc_queue.size()) || (pn_maxsize <= 0))
		{
			return false;
		}
		mn_maxsize = pn_maxsize;
		return true;
	}
protected:
	//不可拷贝不可移动
	SafeQueue(const SafeQueue&) = delete;
	SafeQueue(SafeQueue&&) = delete;
	SafeQueue& operator=(const SafeQueue&) = delete;
	SafeQueue& operator=(SafeQueue&&) = delete;
protected:
	bool mb_block; //是否阻塞标记, true阻塞等待, false立即返回
	uint32 mn_maxsize; //大于等于上限将会加入失败或挂起等待
	std::queue< tpType > mc_queue;
	std::mutex mo_mutex;
	std::condition_variable_any mo_cond_push;
	std::condition_variable_any mo_cond_pop;
	std::atomic mb_push_waiting;
	std::atomic mb_pop_waiting;
};

使用示例:

 

    typedef SafeQueue SafeQueueType;
	void thread_a(SafeQueueType * pp_queue)
	{
		for (uint32 i = 0; i < 20; ++i)
		{
			uint32 zn_val = i + 1;
			bool zb_ok = pp_queue->push(zn_val);
			std::cout << "thread_a ok : " << (zb_ok ? "true" : "false")
				<< ", push : " << zn_val << ", size : " << pp_queue->size()
			<< std::endl;
		}
	}
	void thread_b(SafeQueueType * pp_queue)
	{
		uint32 n = 0;
		while (!pp_queue->empty())
		{
			++n;
			uint32 nout = 0;
			bool zb_ok = pp_queue->pop(nout);
			std::cout << "thread_b ok : " << (zb_ok ? "true" : "false")
				<< ", pop : " << nout << ", size : " << pp_queue->size()
				<< std::endl;
			std::this_thread::sleep_for(std::chrono::seconds(1));
			if (n > 5) { pp_queue->set_block(false); } //切换模式
		}
	}
	void test1()
	{
		SafeQueue zc_num_queue(true, 5);
		std::cout << "--------------" << std::endl;
		uint32 n1 = 100;
		zc_num_queue.push(n1);
		zc_num_queue.push(200);
		std::cout << "queue size : " << zc_num_queue.size() << std::endl;

		uint32 nout = 0;
		zc_num_queue.pop(nout);
		std::cout << "queue pop : " << nout
			<< ", queue size : " << zc_num_queue.size() << std::endl;

		zc_num_queue.clear();

		std::thread ta(thread_a, &zc_num_queue);
		std::thread tb(thread_b, &zc_num_queue);

		ta.join();
		tb.join();

		std::cout << "all finish" << std::endl;
	}

 

你可能感兴趣的:(极品底层(C++))