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