unbounded_fifo_queue.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2015.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file unbounded_fifo_queue.hpp
  9. * \author Andrey Semashev
  10. * \date 24.07.2011
  11. *
  12. * The header contains implementation of unbounded FIFO queueing strategy for
  13. * the asynchronous sink frontend.
  14. */
  15. #ifndef BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
  16. #define BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
  17. #include <boost/log/detail/config.hpp>
  18. #ifdef BOOST_HAS_PRAGMA_ONCE
  19. #pragma once
  20. #endif
  21. #if defined(BOOST_LOG_NO_THREADS)
  22. #error Boost.Log: This header content is only supported in multithreaded environment
  23. #endif
  24. #include <boost/memory_order.hpp>
  25. #include <boost/atomic/atomic.hpp>
  26. #include <boost/log/detail/event.hpp>
  27. #include <boost/log/detail/threadsafe_queue.hpp>
  28. #include <boost/log/core/record_view.hpp>
  29. #include <boost/log/detail/header.hpp>
  30. namespace boost {
  31. BOOST_LOG_OPEN_NAMESPACE
  32. namespace sinks {
  33. /*!
  34. * \brief Unbounded FIFO log record queueing strategy
  35. *
  36. * The \c unbounded_fifo_queue class is intended to be used with
  37. * the \c asynchronous_sink frontend as a log record queueing strategy.
  38. *
  39. * This strategy implements the simplest logic of log record buffering between
  40. * threads: the queue has no limits and imposes no ordering over the queued
  41. * elements aside from the order in which they are enqueued.
  42. * Because of this the queue provides decent performance and scalability,
  43. * however if sink backends can't consume log records fast enough the queue
  44. * may grow uncontrollably. When this is an issue, it is recommended to
  45. * use one of the bounded strategies.
  46. */
  47. class unbounded_fifo_queue
  48. {
  49. private:
  50. typedef boost::log::aux::threadsafe_queue< record_view > queue_type;
  51. private:
  52. //! Thread-safe queue
  53. queue_type m_queue;
  54. //! Event object to block on
  55. boost::log::aux::event m_event;
  56. //! Interruption flag
  57. boost::atomic< bool > m_interruption_requested;
  58. protected:
  59. //! Default constructor
  60. unbounded_fifo_queue() : m_interruption_requested(false)
  61. {
  62. }
  63. //! Initializing constructor
  64. template< typename ArgsT >
  65. explicit unbounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
  66. {
  67. }
  68. //! Enqueues log record to the queue
  69. void enqueue(record_view const& rec)
  70. {
  71. m_queue.push(rec);
  72. m_event.set_signalled();
  73. }
  74. //! Attempts to enqueue log record to the queue
  75. bool try_enqueue(record_view const& rec)
  76. {
  77. // Assume the call never blocks
  78. enqueue(rec);
  79. return true;
  80. }
  81. //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
  82. bool try_dequeue_ready(record_view& rec)
  83. {
  84. return m_queue.try_pop(rec);
  85. }
  86. //! Attempts to dequeue log record from the queue, does not block if the queue is empty
  87. bool try_dequeue(record_view& rec)
  88. {
  89. return m_queue.try_pop(rec);
  90. }
  91. //! Dequeues log record from the queue, blocks if the queue is empty
  92. bool dequeue_ready(record_view& rec)
  93. {
  94. // Try the fast way first
  95. if (m_queue.try_pop(rec))
  96. return true;
  97. // Ok, we probably have to wait for new records
  98. while (true)
  99. {
  100. m_event.wait();
  101. if (m_interruption_requested.exchange(false, boost::memory_order_acquire))
  102. return false;
  103. if (m_queue.try_pop(rec))
  104. return true;
  105. }
  106. }
  107. //! Wakes a thread possibly blocked in the \c dequeue method
  108. void interrupt_dequeue()
  109. {
  110. m_interruption_requested.store(true, boost::memory_order_release);
  111. m_event.set_signalled();
  112. }
  113. };
  114. } // namespace sinks
  115. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  116. } // namespace boost
  117. #include <boost/log/detail/footer.hpp>
  118. #endif // BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_