annotate DEPENDENCIES/generic/include/boost/log/detail/threadsafe_queue.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 /*
Chris@101 2 * Copyright Andrey Semashev 2007 - 2015.
Chris@16 3 * Distributed under the Boost Software License, Version 1.0.
Chris@16 4 * (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 * http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6 */
Chris@16 7 /*!
Chris@16 8 * \file threadsafe_queue.hpp
Chris@16 9 * \author Andrey Semashev
Chris@16 10 * \date 05.11.2010
Chris@16 11 *
Chris@16 12 * \brief This header is the Boost.Log library implementation, see the library documentation
Chris@16 13 * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
Chris@16 14 */
Chris@16 15
Chris@16 16 #ifndef BOOST_LOG_DETAIL_THREADSAFE_QUEUE_HPP_INCLUDED_
Chris@16 17 #define BOOST_LOG_DETAIL_THREADSAFE_QUEUE_HPP_INCLUDED_
Chris@16 18
Chris@16 19 #include <boost/log/detail/config.hpp>
Chris@16 20
Chris@16 21 #ifdef BOOST_HAS_PRAGMA_ONCE
Chris@16 22 #pragma once
Chris@16 23 #endif
Chris@16 24
Chris@16 25 #ifndef BOOST_LOG_NO_THREADS
Chris@16 26
Chris@16 27 #include <new>
Chris@16 28 #include <memory>
Chris@16 29 #include <cstddef>
Chris@16 30 #include <boost/aligned_storage.hpp>
Chris@16 31 #include <boost/move/core.hpp>
Chris@16 32 #include <boost/move/utility.hpp>
Chris@16 33 #include <boost/type_traits/alignment_of.hpp>
Chris@16 34 #include <boost/type_traits/type_with_alignment.hpp>
Chris@16 35 #include <boost/log/detail/header.hpp>
Chris@16 36
Chris@16 37 namespace boost {
Chris@16 38
Chris@16 39 BOOST_LOG_OPEN_NAMESPACE
Chris@16 40
Chris@16 41 namespace aux {
Chris@16 42
Chris@16 43 //! Base class for the thread-safe queue implementation
Chris@16 44 struct threadsafe_queue_impl
Chris@16 45 {
Chris@16 46 struct
Chris@16 47 #if defined(__GNUC__)
Chris@16 48 // Explicitly mark the type so that it may alias other types
Chris@16 49 __attribute__ ((__may_alias__))
Chris@16 50 #endif
Chris@16 51 pointer_storage
Chris@16 52 {
Chris@16 53 union
Chris@16 54 {
Chris@16 55 void* data[2];
Chris@16 56 type_with_alignment< 2 * sizeof(void*) >::type alignment;
Chris@16 57 };
Chris@16 58 };
Chris@16 59
Chris@16 60 struct node_base
Chris@16 61 {
Chris@16 62 pointer_storage next;
Chris@16 63 };
Chris@16 64
Chris@16 65 static BOOST_LOG_API threadsafe_queue_impl* create(node_base* first_node);
Chris@16 66
Chris@16 67 static BOOST_LOG_API void* operator new (std::size_t size);
Chris@16 68 static BOOST_LOG_API void operator delete (void* p, std::size_t);
Chris@16 69
Chris@16 70 virtual ~threadsafe_queue_impl() {}
Chris@16 71 virtual node_base* reset_last_node() = 0;
Chris@16 72 virtual bool unsafe_empty() = 0;
Chris@16 73 virtual void push(node_base* p) = 0;
Chris@16 74 virtual bool try_pop(node_base*& node_to_free, node_base*& node_with_value) = 0;
Chris@16 75 };
Chris@16 76
Chris@16 77 //! A helper class to compose some of the types used by the queue
Chris@16 78 template< typename T, typename AllocatorT >
Chris@16 79 struct threadsafe_queue_types
Chris@16 80 {
Chris@16 81 struct node :
Chris@16 82 public threadsafe_queue_impl::node_base
Chris@16 83 {
Chris@16 84 typedef typename aligned_storage< sizeof(T), alignment_of< T >::value >::type storage_type;
Chris@16 85 storage_type storage;
Chris@16 86
Chris@16 87 node() {}
Chris@16 88 explicit node(T const& val) { new (storage.address()) T(val); }
Chris@16 89 T& value() { return *static_cast< T* >(storage.address()); }
Chris@16 90 void destroy() { static_cast< T* >(storage.address())->~T(); }
Chris@16 91 };
Chris@16 92
Chris@16 93 typedef typename AllocatorT::BOOST_NESTED_TEMPLATE rebind< node >::other allocator_type;
Chris@16 94 };
Chris@16 95
Chris@16 96 /*!
Chris@16 97 * \brief An unbounded thread-safe queue
Chris@16 98 *
Chris@16 99 * The implementation is based on algorithms published in the "Simple, Fast,
Chris@16 100 * and Practical Non-Blocking and Blocking Concurrent Queue Algorithms" article
Chris@16 101 * in PODC96 by Maged M. Michael and Michael L. Scott. Pseudocode is available here:
Chris@16 102 * http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html
Chris@16 103 *
Chris@16 104 * The implementation provides thread-safe \c push and \c try_pop operations, as well as
Chris@16 105 * a thread-unsafe \c empty operation. The queue imposes the following requirements
Chris@16 106 * on the element type:
Chris@16 107 *
Chris@16 108 * \li Default constructible, the default constructor must not throw.
Chris@16 109 * \li Copy constructible.
Chris@16 110 * \li Movable (i.e. there should be an efficient move assignment for this type).
Chris@16 111 *
Chris@16 112 * The last requirement is not mandatory but is crucial for decent performance.
Chris@16 113 */
Chris@16 114 template< typename T, typename AllocatorT = std::allocator< void > >
Chris@16 115 class threadsafe_queue :
Chris@16 116 private threadsafe_queue_types< T, AllocatorT >::allocator_type
Chris@16 117 {
Chris@16 118 private:
Chris@16 119 typedef typename threadsafe_queue_types< T, AllocatorT >::allocator_type base_type;
Chris@16 120 typedef typename threadsafe_queue_types< T, AllocatorT >::node node;
Chris@16 121
Chris@16 122 //! A simple scope guard to automate memory reclaiming
Chris@16 123 struct auto_deallocate;
Chris@16 124 friend struct auto_deallocate;
Chris@16 125 struct auto_deallocate
Chris@16 126 {
Chris@16 127 auto_deallocate(base_type* alloc, node* dealloc, node* destr) :
Chris@16 128 m_pAllocator(alloc),
Chris@16 129 m_pDeallocate(dealloc),
Chris@16 130 m_pDestroy(destr)
Chris@16 131 {
Chris@16 132 }
Chris@16 133 ~auto_deallocate()
Chris@16 134 {
Chris@16 135 m_pAllocator->deallocate(m_pDeallocate, 1);
Chris@16 136 m_pDestroy->destroy();
Chris@16 137 }
Chris@16 138
Chris@16 139 private:
Chris@16 140 base_type* m_pAllocator;
Chris@16 141 node* m_pDeallocate;
Chris@16 142 node* m_pDestroy;
Chris@16 143 };
Chris@16 144
Chris@16 145 public:
Chris@16 146 typedef T value_type;
Chris@16 147 typedef T& reference;
Chris@16 148 typedef T const& const_reference;
Chris@16 149 typedef T* pointer;
Chris@16 150 typedef T const* const_pointer;
Chris@16 151 typedef std::ptrdiff_t difference_type;
Chris@16 152 typedef std::size_t size_type;
Chris@16 153 typedef AllocatorT allocator_type;
Chris@16 154
Chris@16 155 public:
Chris@16 156 /*!
Chris@16 157 * Default constructor, creates an empty queue. Unlike most containers,
Chris@16 158 * the constructor requires memory allocation.
Chris@16 159 *
Chris@16 160 * \throw std::bad_alloc if there is not sufficient memory
Chris@16 161 */
Chris@16 162 threadsafe_queue(base_type const& alloc = base_type()) :
Chris@16 163 base_type(alloc)
Chris@16 164 {
Chris@16 165 node* p = base_type::allocate(1);
Chris@16 166 if (p)
Chris@16 167 {
Chris@16 168 try
Chris@16 169 {
Chris@16 170 new (p) node();
Chris@16 171 try
Chris@16 172 {
Chris@16 173 m_pImpl = threadsafe_queue_impl::create(p);
Chris@16 174 }
Chris@16 175 catch (...)
Chris@16 176 {
Chris@16 177 p->~node();
Chris@16 178 throw;
Chris@16 179 }
Chris@16 180 }
Chris@16 181 catch (...)
Chris@16 182 {
Chris@16 183 base_type::deallocate(p, 1);
Chris@16 184 throw;
Chris@16 185 }
Chris@16 186 }
Chris@16 187 else
Chris@16 188 throw std::bad_alloc();
Chris@16 189 }
Chris@16 190 /*!
Chris@16 191 * Destructor
Chris@16 192 */
Chris@16 193 ~threadsafe_queue()
Chris@16 194 {
Chris@16 195 // Clear the queue
Chris@16 196 if (!unsafe_empty())
Chris@16 197 {
Chris@16 198 value_type value;
Chris@16 199 while (try_pop(value));
Chris@16 200 }
Chris@16 201
Chris@16 202 // Remove the last dummy node
Chris@16 203 node* p = static_cast< node* >(m_pImpl->reset_last_node());
Chris@16 204 p->~node();
Chris@16 205 base_type::deallocate(p, 1);
Chris@16 206
Chris@16 207 delete m_pImpl;
Chris@16 208 }
Chris@16 209
Chris@16 210 /*!
Chris@16 211 * Checks if the queue is empty. Not thread-safe, the returned result may not be actual.
Chris@16 212 */
Chris@16 213 bool unsafe_empty() const { return m_pImpl->unsafe_empty(); }
Chris@16 214
Chris@16 215 /*!
Chris@16 216 * Puts a new element to the end of the queue. Thread-safe, can be called
Chris@16 217 * concurrently by several threads, and concurrently with the \c pop operation.
Chris@16 218 */
Chris@16 219 void push(const_reference value)
Chris@16 220 {
Chris@16 221 node* p = base_type::allocate(1);
Chris@16 222 if (p)
Chris@16 223 {
Chris@16 224 try
Chris@16 225 {
Chris@16 226 new (p) node(value);
Chris@16 227 }
Chris@16 228 catch (...)
Chris@16 229 {
Chris@16 230 base_type::deallocate(p, 1);
Chris@16 231 throw;
Chris@16 232 }
Chris@16 233 m_pImpl->push(p);
Chris@16 234 }
Chris@16 235 else
Chris@16 236 throw std::bad_alloc();
Chris@16 237 }
Chris@16 238
Chris@16 239 /*!
Chris@16 240 * Attempts to pop an element from the beginning of the queue. Thread-safe, can
Chris@16 241 * be called concurrently with the \c push operation. Should not be called by
Chris@16 242 * several threads concurrently.
Chris@16 243 */
Chris@16 244 bool try_pop(reference value)
Chris@16 245 {
Chris@16 246 threadsafe_queue_impl::node_base *dealloc, *destr;
Chris@16 247 if (m_pImpl->try_pop(dealloc, destr))
Chris@16 248 {
Chris@101 249 node* p = static_cast< node* >(destr);
Chris@16 250 auto_deallocate guard(static_cast< base_type* >(this), static_cast< node* >(dealloc), p);
Chris@16 251 value = boost::move(p->value());
Chris@16 252 return true;
Chris@16 253 }
Chris@16 254 else
Chris@16 255 return false;
Chris@16 256 }
Chris@16 257
Chris@16 258 // Copying and assignment is prohibited
Chris@16 259 BOOST_DELETED_FUNCTION(threadsafe_queue(threadsafe_queue const&))
Chris@16 260 BOOST_DELETED_FUNCTION(threadsafe_queue& operator= (threadsafe_queue const&))
Chris@16 261
Chris@16 262 private:
Chris@16 263 //! Pointer to the implementation
Chris@16 264 threadsafe_queue_impl* m_pImpl;
Chris@16 265 };
Chris@16 266
Chris@16 267 } // namespace aux
Chris@16 268
Chris@16 269 BOOST_LOG_CLOSE_NAMESPACE // namespace log
Chris@16 270
Chris@16 271 } // namespace boost
Chris@16 272
Chris@16 273 #include <boost/log/detail/footer.hpp>
Chris@16 274
Chris@16 275 #endif // BOOST_LOG_NO_THREADS
Chris@16 276
Chris@16 277 #endif // BOOST_LOG_DETAIL_THREADSAFE_QUEUE_HPP_INCLUDED_