Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

Better Blocking Queue

5.00/5 (1 vote)
15 Mar 2019MIT 3.6K  
Better blocking queue

In the previous post, we discussed a multi-threaded blocking queue whose implementation was lacking: it was not exception safe. It left the semaphore counts wrongly modified in the presence of exceptions emitted by T‘s copy constructor or assignment operator.

Below is a corrected void push(const T& item) method:

C++
void push(const T& item)
{
	m_openSlots.wait();
	{
		std::lock_guard<std::mutex> lock(m_cs);
		try
		{
			new (m_data + m_pushIndex) T (item);
		}
		catch (...)
		{
			m_openSlots.post();
			throw;
		}
		m_pushIndex = ++m_pushIndex % m_size;
		++m_count;
	}
	m_fullSlots.post();
}

In the corrected version, we first catch any exception possibly emitted by T‘s copy constructor, then adjust back the open-slot semaphore. Since the push operation failed, the number of open and full slots has not changed. Finally, we re-throw the exception.

Below is a corrected void pop(T& item) method:

C++
void pop(T& item)
{
	m_fullSlots.wait();
	{
		std::lock_guard<std::mutex> lock(m_cs);
		try
		{
			item = m_data[m_popIndex];
		}
		catch (...)
		{
			m_fullSlots.post();
			throw;
		}
		m_data[m_popIndex].~T();
		m_popIndex = ++m_popIndex % m_size;
		--m_count;
	}
	m_openSlots.post();
}

In the corrected version, we first catch any exception possibly emitted by T‘s assignment operator, then adjust back the full-slot semaphore. Since the pop operation failed, the number of open and full slots did not change. Finally, we re-throw the exception.

We now have a robust queue template class that can handle misbehaving Ts. 🙂

License

This article, along with any associated source code and files, is licensed under The MIT License