1 // lock-free fifo queue from
2 // Michael, M. M. and Scott, M. L.,
3 // "simple, fast and practical non-blocking and blocking concurrent queue algorithms"
5 // implementation for c++
7 // Copyright (C) 2008 Tim Blechmann
9 // Distributed under the Boost Software License, Version 1.0. (See
10 // accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
13 // Disclaimer: Not a Boost library.
15 #ifndef BOOST_LOCKFREE_FIFO_HPP_INCLUDED
16 #define BOOST_LOCKFREE_FIFO_HPP_INCLUDED
18 #include <boost/atomic.hpp>
19 #include <boost/lockfree/detail/tagged_ptr.hpp>
20 #include <boost/lockfree/detail/freelist.hpp>
22 #include <boost/static_assert.hpp>
23 #include <boost/type_traits/is_pod.hpp>
25 #include <memory> /* std::auto_ptr */
26 #include <boost/scoped_ptr.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/noncopyable.hpp>
38 template <typename T
, typename freelist_t
, typename Alloc
>
42 BOOST_STATIC_ASSERT(boost::is_pod
<T
>::value
);
44 struct BOOST_LOCKFREE_CACHELINE_ALIGNMENT node
46 typedef tagged_ptr
<node
> tagged_ptr_t
;
51 /* increment tag to avoid ABA problem */
52 tagged_ptr_t old_next
= next
.load(memory_order_acquire
);
53 tagged_ptr_t
new_next (NULL
, old_next
.get_tag()+1);
54 next
.store(new_next
, memory_order_release
);
58 next(tagged_ptr_t(NULL
, 0))
61 atomic
<tagged_ptr_t
> next
;
65 typedef tagged_ptr
<node
> atomic_node_ptr
;
67 typedef typename
Alloc::template rebind
<node
>::other node_allocator
;
68 /* typedef typename select_freelist<node, node_allocator, freelist_t>::type pool_t; */
70 typedef typename
boost::mpl::if_
<boost::is_same
<freelist_t
, caching_freelist_t
>,
71 caching_freelist
<node
, node_allocator
>,
72 static_freelist
<node
, node_allocator
>
76 static const bool is_lockfree
= node::tagged_ptr_t::is_lockfree
;
81 node
* n
= alloc_node();
86 explicit fifo(std::size_t initial_nodes
):
89 node
* n
= alloc_node();
101 if (!dequeue(&dummy
))
105 dealloc_node(head_
.get_ptr());
110 return head_
.get_ptr() == tail_
.get_ptr();
113 bool enqueue(T
const & t
)
115 node
* n
= alloc_node(t
);
122 atomic_node_ptr
tail (tail_
);
123 read_memory_barrier();
124 atomic_node_ptr
next (tail
->next
);
126 if (likely(tail
== tail_
))
128 if (next
.get_ptr() == 0)
130 if ( tail
->next
.compare_exchange_strong(next
, tagged_ptr
<node
>(n
, next
.get_tag() + 1)) )
137 tail_
.cas(tail
, next
.get_ptr());
142 bool dequeue (T
* ret
)
146 atomic_node_ptr
head (head_
);
147 read_memory_barrier();
149 atomic_node_ptr
tail(tail_
);
150 node
* next
= head
->next
.load(memory_order_acquire
).get_ptr();
151 read_memory_barrier();
153 if (likely(head
== head_
))
155 if (head
.get_ptr() == tail
.get_ptr())
160 tail_
.cas(tail
, next
);
165 if (head_
.cas(head
, next
))
167 dealloc_node(head
.get_ptr());
177 node
* alloc_node(void)
179 node
* chunk
= pool
.allocate();
184 node
* alloc_node(T
const & t
)
186 node
* chunk
= pool
.allocate();
191 void dealloc_node(node
* n
)
197 volatile atomic_node_ptr head_
;
198 static const int padding_size
= 64 - sizeof(atomic_node_ptr
); /* cache lines on current cpus seem to
200 char padding1
[padding_size
];
201 volatile atomic_node_ptr tail_
;
202 char padding2
[padding_size
];
207 } /* namespace detail */
211 * - wrapper for detail::fifo
213 template <typename T
,
214 typename freelist_t
= caching_freelist_t
,
215 typename Alloc
= std::allocator
<T
>
218 public detail::fifo
<T
, freelist_t
, Alloc
>
224 explicit fifo(std::size_t initial_nodes
):
225 detail::fifo
<T
, freelist_t
, Alloc
>(initial_nodes
)
230 /** lockfree fifo, template specialization for pointer-types
232 * - wrapper for detail::fifo
233 * - overload dequeue to support smart pointers
235 template <typename T
, typename freelist_t
, typename Alloc
>
236 class fifo
<T
*, freelist_t
, Alloc
>:
237 public detail::fifo
<T
*, freelist_t
, Alloc
>
239 typedef detail::fifo
<T
*, freelist_t
, Alloc
> fifo_t
;
241 template <typename smart_ptr
>
242 bool dequeue_smart_ptr(smart_ptr
& ptr
)
245 bool success
= fifo_t::dequeue(&result
);
256 explicit fifo(std::size_t initial_nodes
):
257 fifo_t(initial_nodes
)
262 return fifo_t::enqueue(t
);
265 bool dequeue (T
** ret
)
267 return fifo_t::dequeue(ret
);
270 bool dequeue (std::auto_ptr
<T
> & ret
)
272 return dequeue_smart_ptr(ret
);
275 bool dequeue (boost::scoped_ptr
<T
> & ret
)
277 BOOST_STATIC_ASSERT(sizeof(boost::scoped_ptr
<T
>) == sizeof(T
*));
278 return dequeue(reinterpret_cast<T
**>((void*)&ret
));
281 bool dequeue (boost::shared_ptr
<T
> & ret
)
283 return dequeue_smart_ptr(ret
);
287 } /* namespace lockfree */
288 } /* namespace boost */
291 #endif /* BOOST_LOCKFREE_FIFO_HPP_INCLUDED */