Files
fail/src/core/util/SynchronizedQueue.hpp
Horst Schirmeier 8505ddbb04 jobserver: synchronization cleanup
This change cleans up in/out queue synchronization in the job server.
End-of-jobs conditions are now properly signaled through the
SynchronizedQueue, allowing to resume and abort blocked readers when
no more input is expected.

Change-Id: I3eaf37115ccf8c5b5afe3d971c7109cd62b68906
2014-01-20 22:48:08 +01:00

140 lines
3.1 KiB
C++

/**
* \brief Queue class that has thread synchronisation.
*/
#ifndef __SYNCHRONIZED_QUEUE_HPP__
#define __SYNCHRONIZED_QUEUE_HPP__
#include <queue>
#ifndef __puma
#include <boost/thread.hpp>
#endif
namespace fail {
template <typename T>
class SynchronizedQueue { // Adapted from: http://www.quantnet.com/cplusplus-multithreading-boost/
private:
std::queue<T> m_queue; //!< Use STL queue to store data
unsigned capacity;
bool finished;
#ifndef __puma
boost::mutex m_mutex; //!< The mutex to synchronise on
boost::condition_variable m_cond; //!< The condition to wait for
boost::condition_variable m_cond_capacity; //!< Another condition to wait for
#endif
public:
SynchronizedQueue() : capacity(0), finished(false) {}
SynchronizedQueue(unsigned capacity) : capacity(capacity), finished(false) {}
int Size()
{
#ifndef __puma
boost::unique_lock<boost::mutex> lock(m_mutex);
#endif
return m_queue.size();
}
// Add data to the queue and notify others
void Enqueue(const T& data)
{
// Acquire lock on the queue
#ifndef __puma
boost::unique_lock<boost::mutex> lock(m_mutex);
#endif
while (capacity != 0 && m_queue.size() >= capacity) {
#ifndef __puma
m_cond_capacity.wait(lock);
#endif
}
// Add the data to the queue
m_queue.push(data);
// Notify others that data is ready
#ifndef __puma
m_cond.notify_one();
#endif
} // Lock is automatically released here
/**
* Get data from the queue. Wait for data if not available
*/
T Dequeue()
{
// Acquire lock on the queue
#ifndef __puma
boost::unique_lock<boost::mutex> lock(m_mutex);
#endif
// When there is no data, wait till someone fills it.
// Lock is automatically released in the wait and obtained
// again after the wait
#ifndef __puma
while (m_queue.size() == 0) {
if (finished) {
// default-constructed T, 0 for integral types
return T();
}
m_cond.wait(lock);
}
#endif
// Retrieve the data from the queue
T result = m_queue.front();
m_queue.pop();
// Notify others that we have free slots
#ifndef __puma
if (m_queue.size() < capacity) {
m_cond_capacity.notify_one();
}
#endif
return result;
} // Lock is automatically released here
/**
* Get data from the queue. Non blocking variant.
* @param d Pointer to copy queue element to
* @return false if no element in queue
*
*/
bool Dequeue_nb(T& d)
{
// Acquire lock on the queue
#ifndef __puma
boost::unique_lock<boost::mutex> lock(m_mutex);
#endif
// When there is no data, return false.
// Lock is automatically released in the wait and obtained
// again after the wait
if (m_queue.size() > 0) {
// Retrieve the data from the queue
d = m_queue.front();
m_queue.pop();
// Notify others that we have free slots
#ifndef __puma
if (m_queue.size() < capacity) {
m_cond_capacity.notify_one();
}
#endif
return true;
} else {
return false;
}
} // Lock is automatically released here
void setIsFinished(bool value = true)
{
#ifndef __puma
boost::unique_lock<boost::mutex> lock(m_mutex);
#endif
finished = value;
#ifndef __puma
m_cond.notify_all();
#endif
}
};
} // end-of-namespace: fail
#endif // __SYNCHRONIZED_QUEUE_HPP__