#ifndef _SAFEQUEUE_H_
|
#define _SAFEQUEUE_H_
|
|
#include <queue>
|
#include <condition_variable>
|
#include <mutex>
|
#include <chrono>
|
#include <limits> // std::numeric_limits<>::max
|
|
#define SAFE_QUEUE_DEFAULT_MAX_SIZE std::numeric_limits<std::size_t >::max()
|
|
/// @brief thread-safe queue
|
/// It uses a mutex+condition variables to protect the internal queue
|
/// implementation. Inserting or reading elements use the same mutex
|
template <typename T>
|
class SafeQueue
|
{
|
public:
|
/// @brief constructor
|
/// @param a_maxSize optional parameter with the maximum size of the queue
|
SafeQueue(std::size_t a_maxSize = SAFE_QUEUE_DEFAULT_MAX_SIZE);
|
|
/// @brief destructor
|
~SafeQueue();
|
|
/// @brief copy contructor
|
/// WARNING: Use with great care, this function call can take a long time
|
/// and block other threads from pushing/popping elements into the source
|
/// queue
|
SafeQueue(const SafeQueue<T>& a_src);
|
|
/// @brief operator= overloading
|
/// This function blocks the a_src and "this" SafeQueues and copies the
|
/// contents of a_src into "this" SafeQueue.
|
/// WARNING: Use with great care, this function call can take a long time
|
/// and block other threads from pushing/popping elements into the queues
|
/// @param a_src the "right" side of the operator=
|
/// @return a const reference to this object
|
const SafeQueue<T>& operator=(const SafeQueue<T> &a_src);
|
|
/// @brief move contructor
|
SafeQueue(SafeQueue<T>&& a_src);
|
|
/// @brief move assignment
|
SafeQueue<T>& operator=(SafeQueue<T>&& a_src);
|
|
/// @brief Check if the queue is empty
|
/// This call can block if another thread owns the lock that protects the
|
/// queue
|
/// @return true if the queue is empty. False otherwise
|
bool isEmpty() const;
|
|
/// @brief inserts an element into queue queue
|
/// This call can block if another thread owns the lock that protects the
|
/// queue. If the queue is full The thread will be blocked in this queue
|
/// until someone else gets an element from the queue
|
/// @param element to insert into the queue
|
void push(const T &a_elem);
|
|
/// @brief inserts an element into queue queue
|
/// This call can block if another thread owns the lock that protects the
|
/// queue. If the queue is full The call will return false and the element
|
/// won't be inserted
|
/// @param element to insert into the queue
|
/// @return True if the elem was successfully inserted into the queue.
|
/// False otherwise
|
bool tryPush(const T &a_elem);
|
|
/// @brief extracts an element from the queue (and deletes it from the q)
|
/// If the queue is empty this call will block the thread until there is
|
/// something in the queue to be extracted
|
/// @param a reference where the element from the queue will be saved to
|
void pop(T &out_data);
|
|
/// @brief extracts an element from the queue (and deletes it from the q)
|
/// This call gets the block that protects the queue. It will extract the
|
/// element from the queue only if there are elements in it
|
/// @param reference to the variable where the result will be saved
|
/// @return True if the element was retrieved from the queue.
|
/// False if the queue was empty
|
bool tryPop(T &out_data);
|
|
/// @brief extracts an element from the queue (and deletes it from the q)
|
/// If the queue is empty this call will block the thread until there
|
/// is something in the queue to be extracted or until the timer
|
/// (2nd parameter) expires
|
/// @param reference to the variable where the result will be saved
|
/// @param duration to wait before returning if the queue was empty
|
/// you may also pass into this a std::seconds or std::milliseconds
|
/// (defined in std::chrono)
|
/// @return True if the element was retrieved from the queue.
|
/// False if the timeout was hit and nothing could be extracted
|
/// from the queue
|
bool timedWaitPop(T &data, std::chrono::microseconds a_microsecs);
|
|
protected:
|
/// the actual queue data structure protected by this SafeQueue wrapper
|
std::queue<T> m_theQueue;
|
/// maximum number of elements for the queue
|
std::size_t m_maximumSize;
|
/// Mutex to protect the queue
|
mutable std::mutex m_mutex;
|
/// Conditional variable to wake up threads
|
mutable std::condition_variable m_cond;
|
|
/// @brief calculate if copying a_src into this instance will need to
|
/// wake up potential threads waiting to perform push or pop ops.
|
/// WARNING: It assumes the caller holds all mutexes required to access
|
/// to the data of this and a_src SafeQueues
|
/// @param a_src const reference to the SafeQueue that will be copied
|
/// into this object
|
/// @return true if threads will need to be waken up. False otherwise
|
inline bool wakeUpSignalNeeded(const SafeQueue<T> &a_src) const;
|
};
|
|
// include the implementation file
|
#include "safe_queue_impl.h"
|
|
#endif /* _SAFEQUEUE_H_ */
|