text: /*
   * threadsafe_queue2.h
   *
   * Lock-based wait-free thread-safe unbounded queue implemented using library queue,
   * locks, and a single mutex.
   *
   */
  
  #ifndef THREADSAFE_QUEUE2_H_
  #define THREADSAFE_QUEUE2_H_
  
  #include <queue> // std::queue
  #include <memory> // std::unique_ptr
  #include <list> // std::list
  #include <utility> // std::move
  #include <mutex> // std::mutex, std::lock_guard, std::unique_lock
  #include <exception> // std::exception
  
  template<typename Element>
  class ThreadSafeQueue2 {
  	typedef std::unique_ptr<Element> ElementPtr;
  	typedef std::list<ElementPtr> Container;
  
  	struct EmptyQueue: public std::exception {
  		virtual const char* what() const noexcept (true) override {
  			return "Empty Queue";
  		}
  	};
  
  public:
  	ThreadSafeQueue2(void) :
  			m_data(std::queue<ElementPtr, Container>()) {
  	}
  	~ThreadSafeQueue2() = default;
  	ThreadSafeQueue2(const ThreadSafeQueue2&) = delete;
  	ThreadSafeQueue2& operator=(const ThreadSafeQueue2&) = delete;
  
  	bool empty(void) {
  		std::lock_guard<std::mutex> lock(m_mutex);
  		return m_data.empty();
  	}
  
  	size_t size(void) {
  		std::lock_guard<std::mutex> lock(m_mutex);
  		return m_data.size();
  	}
  
  	void push(const Element &value) {
  		ElementPtr new_element(std::make_unique<Element>(value));
  		std::lock_guard<std::mutex> lock(m_mutex);
  		m_data.push(std::move(new_element));
  	}
  
  	void push(Element &&value) {
  		ElementPtr new_element(std::make_unique<Element>(std::move(value)));
  		std::lock_guard<std::mutex> lock(m_mutex);
  		m_data.push(std::move(new_element));
  	}
  
  	template<typename ...Ts>
  	void emplace(Ts &&... pars) {
  		ElementPtr new_element(std::make_unique<Element>(std::forward<Ts>(pars)...));
  		std::lock_guard<std::mutex> lock(m_mutex);
  		m_data.push(std::move(new_element));
  	}
  
  	const ElementPtr getFrontAndPop(void) {
  		std::lock_guard<std::mutex> lock(m_mutex);
  		if (m_data.empty())
  			return std::make_unique<Element>();
  		else {
  			ElementPtr front_element(std::move(m_data.front()));
  			m_data.pop();
  			return front_element;
  		}
  	}
  
  private:
  	mutable std::mutex m_mutex;
  	std::queue<ElementPtr, Container> m_data;
  };
  
  #endif /* THREADSAFE_QUEUE2_H_ */
  