boost/log/sinks/unbounded_fifo_queue.hpp
/*
* 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 <boost/log/detail/config.hpp>
#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 <boost/memory_order.hpp>
#include <boost/atomic/atomic.hpp>
#include <boost/log/detail/event.hpp>
#include <boost/log/detail/threadsafe_queue.hpp>
#include <boost/log/core/record_view.hpp>
#include <boost/log/detail/header.hpp>
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 <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_