/* * Copyright Andrey Semashev 2007 - 2015. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ /*! * \file unbounded_fifo_queue.hpp * \author Andrey Semashev * \date 24.07.2011 * * The header contains implementation of unbounded FIFO queueing strategy for * the asynchronous sink frontend. */ #ifndef BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_ #define BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_ #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif #if defined(BOOST_LOG_NO_THREADS) #error Boost.Log: This header content is only supported in multithreaded environment #endif #include #include #include #include #include #include namespace boost { BOOST_LOG_OPEN_NAMESPACE namespace sinks { /*! * \brief Unbounded FIFO log record queueing strategy * * The \c unbounded_fifo_queue class is intended to be used with * the \c asynchronous_sink frontend as a log record queueing strategy. * * This strategy implements the simplest logic of log record buffering between * threads: the queue has no limits and imposes no ordering over the queued * elements aside from the order in which they are enqueued. * Because of this the queue provides decent performance and scalability, * however if sink backends can't consume log records fast enough the queue * may grow uncontrollably. When this is an issue, it is recommended to * use one of the bounded strategies. */ class unbounded_fifo_queue { private: typedef boost::log::aux::threadsafe_queue< record_view > queue_type; private: //! Thread-safe queue queue_type m_queue; //! Event object to block on boost::log::aux::event m_event; //! Interruption flag boost::atomic< bool > m_interruption_requested; protected: //! Default constructor unbounded_fifo_queue() : m_interruption_requested(false) { } //! Initializing constructor template< typename ArgsT > explicit unbounded_fifo_queue(ArgsT const&) : m_interruption_requested(false) { } //! Enqueues log record to the queue void enqueue(record_view const& rec) { m_queue.push(rec); m_event.set_signalled(); } //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { // Assume the call never blocks enqueue(rec); return true; } //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty bool try_dequeue_ready(record_view& rec) { return m_queue.try_pop(rec); } //! Attempts to dequeue log record from the queue, does not block if the queue is empty bool try_dequeue(record_view& rec) { return m_queue.try_pop(rec); } //! Dequeues log record from the queue, blocks if the queue is empty bool dequeue_ready(record_view& rec) { // Try the fast way first if (m_queue.try_pop(rec)) return true; // Ok, we probably have to wait for new records while (true) { m_event.wait(); if (m_interruption_requested.exchange(false, boost::memory_order_acquire)) return false; if (m_queue.try_pop(rec)) return true; } } //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { m_interruption_requested.store(true, boost::memory_order_release); m_event.set_signalled(); } }; } // namespace sinks BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost #include #endif // BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_