1 [library Boost.Lockfree
3 [authors [Blechmann, Tim]]
4 [copyright 2008-2009 Tim Blechmann]
7 lockfree concurrent data structures
12 Distributed under the Boost Software License, Version 1.0.
13 (See accompanying file LICENSE_1_0.txt or copy at
14 [@http://www.boost.org/LICENSE_1_0.txt])
23 [def _note_ [$images/note.png]]
24 [def _alert_ [$images/caution.png]]
25 [def _detail_ [$images/note.png]]
26 [def _tip_ [$images/tip.png]]
30 [def _lockfree_ [^boost.lockfree]]
32 [/ unspecified stuff ]
33 [def __unspecified_int__ /unspecified-int-type/]
34 [def __unspecified_bool__ /unspecified-bool-type/]
36 [section:disclaimer Disclaimer]
37 _lockfree_ is NOT a boost library!
40 [section Introduction]
42 [h2 What is _lockfree_?]
44 _lockfree_ provides implementations of lock-free data structures. Lock-free data structures can be accessed by multiple
45 threads without the necessity of blocking synchronization primitives such as guards. Lock-free data structures can be
46 used in real-time systems, where blocking algorithms may lead to high worst-case execution times, to avoid priority
47 inversion, or to increase the scalability for multi-processor machines.
49 The following data structures are provided:
51 * [classref boost::lockfree::fifo], a lock-free fifo queue
52 * [classref boost::lockfree::stack], a lock-free stack
53 * [classref boost::lockfree::atomic_int], an atomic integer class
62 The [classref boost::lockfree::atomic_int boost::lockfree::atomic_int] class implements fully synchronized atomic
66 #include <boost/thread/thread.hpp>
67 #include <boost/lockfree/atomic_int.hpp>
70 boost::lockfree::atomic_int<int> counter(0);
72 const int iterations = 10000000;
74 void increment_counter(void)
76 for (int i = 0; i != iterations; ++i)
80 void decrement_counter(void)
82 for (int i = 0; i != iterations; ++i)
86 int main(int argc, char* argv[])
88 // incrementing counter in one thread, decrementing in another
89 boost::thread thrd_inc(increment_counter);
90 boost::thread thrd_dec(decrement_counter);
95 std::cout << "counter value is " << counter << "." << std::endl;
99 This program outputs the following:
109 The [classref boost::lockfree::fifo boost::lockfree::fifo] class implements a multi-writer/multi-reader fifo queue. The
110 following example shows how integer values are produced and consumed by 2 threads each:
113 #include <boost/thread/thread.hpp>
114 #include <boost/lockfree/atomic_int.hpp>
115 #include <boost/lockfree/fifo.hpp>
118 boost::lockfree::atomic_int<int> producer_count(0);
119 boost::lockfree::atomic_int<int> consumer_count(0);
121 boost::lockfree::fifo<int> fifo;
123 const int iterations = 1000000;
127 for (int i = 0; i != iterations; ++i) {
128 int value = ++producer_count;
136 while (producer_count != 2*iterations) {
137 while (fifo.dequeue(&value))
141 while (fifo.dequeue(&value))
145 int main(int argc, char* argv[])
147 boost::thread thrd_p1(producer);
148 boost::thread thrd_p2(producer);
149 boost::thread thrd_c1(consumer);
150 boost::thread thrd_c2(consumer);
157 std::cout << "produced " << producer_count << " objects." << std::endl;
158 std::cout << "consumed " << consumer_count << " objects." << std::endl;
162 The program output is:
165 produced 2000000 objects.
166 consumed 2000000 objects.
172 The [classref boost::lockfree::stack boost::lockfree::stack] class implements a multi-writer/multi-reader stack. The
173 following example shows how integer values are produced and consumed by 2 threads each:
176 #include <boost/thread/thread.hpp>
177 #include <boost/lockfree/atomic_int.hpp>
178 #include <boost/lockfree/stack.hpp>
181 boost::lockfree::atomic_int<int> producer_count(0);
182 boost::lockfree::atomic_int<int> consumer_count(0);
184 boost::lockfree::stack<int> stack;
186 const int iterations = 1000000;
190 for (int i = 0; i != iterations; ++i) {
191 int value = ++producer_count;
199 while (producer_count != 2*iterations) {
200 while (stack.pop(&value))
204 while (stack.pop(&value))
209 int main(int argc, char* argv[])
211 boost::thread thrd_p1(producer);
212 boost::thread thrd_p2(producer);
213 boost::thread thrd_c1(consumer);
214 boost::thread thrd_c2(consumer);
221 std::cout << "produced " << producer_count << " objects." << std::endl;
222 std::cout << "consumed " << consumer_count << " objects." << std::endl;
225 The program output is:
228 produced 2000000 objects.
229 consumed 2000000 objects.
239 [section boost::lockfree::fifo]
241 [classref boost::lockfree::fifo boost::lockfree::fifo] provides a multi-writer/multi-reader lockfree fifo class,
242 enqueueing and dequeueing is lockfree, construction/destruction has to be synchronized. A specialized [classref
243 boost::lockfree::fifo fifo] class for pointer-arguments is provided, which supports dequeueing to stl/boost-style smart
244 pointers. Its used type argument is limited to PODs.
246 It uses a freelist for memory management, freed nodes are pushed to the freelist, but not returned to the os. This may
247 result in leaking memory.
258 template <typename T, typename freelist_t = caching_freelist_t, typename Alloc = std::allocator<T> >
264 explicit fifo(std::size_t initial_nodes);
267 bool empty(void) const;
269 bool enqueue(T const & t);
270 bool dequeue(T * ret);
273 template <typename T, typename freelist_t = caching_freelist_t, typename Alloc = std::allocator<T> >
279 explicit fifo(std::size_t initial_nodes);
282 bool empty(void) const;
286 bool dequeue (T ** ret);
287 bool dequeue (std::auto_ptr<T> & ret);
288 bool dequeue (boost::scoped_ptr<T> & ret);
289 bool dequeue (boost::shared_ptr<T> & ret);
292 } /* namespace lockfree */
293 } /* namespace boost */
300 [heading Constructors]
306 explicit fifo(std::size_t initial_nodes);
308 Construct fifo with a number of initially allocated fifo nodes.
314 Destroys stored nodes and fifo, free all nodes from freelist.
316 [warning Not thread-safe, no enqueue/dequeue operation is allowed, when the destructor is running]
320 bool empty(void) const;
322 Returns: true, if fifo is empty.
324 [warning Not thread-safe, use for debugging purposes only]
329 bool enqueue(T const & t);
331 Enqueues object t to the fifo. Enqueueing may fail, if the freelist is not able to allocate a new fifo node.
333 Returns: true, if the enqueue operation is successful.
335 [note Thread-safe and non-blocking]
336 [important May block if node needs to be allocated from the operating system]
340 bool dequeue (T * ret);
342 Dequeue object from fifo.
344 Returns: true, if the dequeue operation is successful, false if fifo was empty.
346 Effect: if dequeue operation is successful, object is written to memory location denoted by ret.
348 [note Thread-safe and non-blocking]
350 bool dequeue (std::auto_ptr<T> & ret);
351 bool dequeue (boost::scoped_ptr<T> & ret);
352 bool dequeue (boost::shared_ptr<T> & ret);
354 The specialized class for pointer objects provides an api for dequeuing objects directly to smart pointers.
358 [section Memory Management]
360 The memory management of the fifo can be controlled via its `freelist_t` template argument. Two different freelists can
361 be used. `struct caching_freelist_t` selects a caching freelist, which can allocate more nodes from the operating
362 system, and `struct static_freelist_t` uses a fixed-sized freelist. With a fixed-sized freelist, the enqueue operation
363 may fail, while with a caching freelist, the enqueue operation may block.
370 [section boost::lockfree::stack]
372 [classref boost::lockfree::stack boost::lockfree::stack] provides a multi-writer/multi-reader lockfree stack class,
373 push and pop is lockfree, construction/destruction has to be synchronized.
375 It uses a caching freelist for memory management, freed nodes are pushed to the freelist. This may result in leaking
387 template <typename T, typename Alloc = std::allocator<T> >
393 explicit stack(std::size_t n);
395 bool empty(void) const;
397 bool push(T const & v);
401 } /* namespace lockfree */
402 } /* namespace boost */
409 [heading Constructors]
415 explicit stack(std::size_t initial_nodes);
417 Construct stack with a number of initially allocated stack nodes.
424 Destroys stack, free all nodes from freelist.
428 bool empty(void) const;
430 Returns: true, if stack is empty.
432 [warning Not thread-safe, use for debugging purposes only]
437 bool push(T const & t);
439 Pushes object t to the stack. Pushing may fail, if the freelist is not able to allocate a new stack node.
441 [note Thread-safe and non-blocking]
442 [important May block, if node needs to be allocated from the operating system]
448 Pop object from stack.
450 Returns: true, if the pop operation is successful, false if stack was empty.
451 Effect: if pop operation is successful, object is written to memory location denoted by ret.
453 [note Thread-safe and non-blocking]
457 [section Memory Management]
459 The memory management of the stack can be controlled via its `freelist_t` template argument. Two different freelists can
460 be used. `struct caching_freelist_t` selects a caching freelist, which can allocate more nodes from the operating
461 system, and `struct static_freelist_t` uses a fixed-sized freelist. With a fixed-sized freelist, the push operation
462 may fail, while with a caching freelist, the push operation may block.
468 [section boost::lockfree::atomic_int]
470 [classref boost::lockfree::atomic_int boost::lockfree::atomic_int] provides an implementation for atomic integers. It
471 does not provide the full interface of integer numbers, but a limited subset, that can be implemented with atomic
472 operations. Modifying an atomic integer acts as full memory barrier.
480 template <typename T>
481 class boost::lockfree::atomic_int:
484 explicit atomic_int(T v = 0);
486 operator T(void) const;
487 void operator =(T v);
499 } /* namespace lockfree */
500 } /* namespace boost */
507 [heading Constructor]
509 explicit atomic_int(T v = 0);
511 Initializes atomic_int to value v
515 operator T(void) const;
517 Returns: Integer value of atomic_int
519 [heading In-Place Operators]
523 Returns: T(*this) + v
525 Effect: T(*this) = T(*this) + v
529 Returns: T(*this) - v
531 Effect: T(*this) = T(*this) - v
534 [heading Prefix Operators]
538 Effect: increments value
540 Returns: value before incrementing
544 Effect: decrements value
546 Returns: value before decrementing
548 [heading Postfix Operators]
552 Effect: increments value
554 Returns: value after incrementing
558 Effect: decrements value
560 Returns: value after decrementing
571 [section Building blocks]
572 The _lockfree_ library provides several building blocks, used in lockfree algorithms.
577 Tagged pointer implementation as smart pointer class, as it is required by several lockfree algorithms.
590 typedef __unspecified_int__ tag_t;
593 tagged_ptr(tagged_ptr const & p);
594 explicit tagged_ptr(T * p, tag_t t = 0);
596 void operator= (tagged_ptr const & p);
597 void atomic_set(tagged_ptr const & p);
598 void atomic_set(T * p, tag_t t);
600 void set(tagged_ptr const & p);
601 void set(T * p, tag_t t);
603 bool operator== (tagged_ptr const & p) const;
604 bool operator!= (tagged_ptr const & p) const;
609 tag_t get_tag() const;
610 void set_tag(tag_t t);
612 bool cas(tagged_ptr const & oldval, T * newptr);
613 bool cas(tagged_ptr const & oldval, T * newptr, tag_t t);
615 T & operator*() const;
616 T * operator->() const;
618 operator __unspecified_bool__(void) const;
621 } /* namespace lockfree */
622 } /* namespace boost */
631 typedef __unspecified_int__ tag_t;
633 Type of ABA-prevention tag
635 [heading Constructors]
639 Uninitialized constructor
641 tagged_ptr(tagged_ptr const & p);
645 explicit tagged_ptr(T * p, tag_t t = 0);
647 Construct tagged_ptr from pointer and tag
650 [heading Atomically Set]
652 void operator= (tagged_ptr const & p);
653 void atomic_set(tagged_ptr const & p);
655 Atomically set from tagged_ptr.
657 void atomic_set(T * p, tag_t t);
659 Atomically set from pointer and tag
662 void set(tagged_ptr const & p);
666 void set(T * p, tag_t t);
668 Set from pointer and tag
671 bool operator== (tagged_ptr const & p) const;
672 bool operator!= (tagged_ptr const & p) const;
674 Returns: (get_ptr() == p.get_ptr()) && (get_tag() == p.get_tag())
676 [heading Pointer access]
689 tag_t get_tag() const;
693 void set_tag(tag_t t);
697 [heading Compare-And-Swap]
699 bool cas(tagged_ptr const & oldval, T * newptr);
701 if (*this == oldval) {
702 this->set(newptr, oldval.get_tag() + 1);
708 bool cas(tagged_ptr const & oldval, T * newptr, tag_t t);
710 if (*this == oldval) {
711 this->set(newptr, t);
717 [heading Indirection]
718 T & operator*() const;
720 Returns: reference to object, undefined if get_ptr() == 0
722 T * operator->() const;
724 Returns: pointer to object
728 operator __unspecified_bool__(void) const;
730 Returns: get_ptr() != 0
739 [section Freelist Concept]
742 template <typename T, typename Alloc = std::allocator<T> >
747 explicit freelist(std::size_t initial_nodes);
751 void deallocate (T * n);
761 [heading Constructors]
767 explicit freelist(std::size_t initial_nodes);
769 Construct freelist, allocate a number of initial nodes
776 Free all nodes from the freelist to the OS
783 Allocate memory for one object.
786 [heading Deallocation]
788 void deallocate (T * n);
790 Deallocate object to freelist
794 [section Freelist Implementations]
796 template <typename T, typename Alloc = std::allocator<T> >
797 class caching_freelist;
799 Caching freelist class. Uses an internal lockfree stack to cache objects. Deallocation never frees objects.
801 template <typename T, std::size_t max_size = 64,
802 typename Alloc = std::allocator<T> >
805 Freelist class, with a maximum size of max_size. Uses an lockfree stack to cache max_size objects.
816 The _lockfree_ library provides platform-specific wrappers for low-level operations.
818 [section Memory Barriers]
819 void boost::lockfree::detail::memory_barrier(void);
825 [section Compare-and-Swap]
827 Lockfree on supported platforms, otherwise blocking emulation.
830 inline bool boost::lockfree::detail::atomic_cas(volatile C * addr, C old, C nw);
832 Single-word compare-and-swap
834 template <class C, class D, class E>
835 inline bool boost::lockfree::detail::atomic_cas2(volatile C * addr, D old1, E old2, D new1, E new2);
837 Double-word compare-and-swap
845 [section Portability]
847 Most data structures of _lockfree_ are written to use of Compare-And-Swap instructions. In order to implement the
848 tagged_ptr, CAS instructions are required, that can operate on one pointer and one integer type. For non-supported
849 platforms, a blocking emulation of the atomic instructions is provided.
851 Tested architectures:
858 * gcc-4.2, gcc-4.3, gcc-4.4
863 [section Acknowledgements]
865 Thanks for suggestions, porting, testing:
867 * Thomas Grill, original win32/osx code pieces
868 * Shiwei Xu, api suggestions
869 * Stefan Eilemann, bug fixes
870 * Mignon Belongie, bug fix
871 * Anthony Williams, found fifo race condition
872 * Casey McCandless, msvc/icc fixes
873 * Mark Bulas, msvc/x64 fixes
874 * Anteru, api/documentation suggestions
880 # Maged M. Michael and Michael L. Scott. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms. In Symposium on Principles of Distributed Computing, pages 267–275, 1996.
881 # M. Herlihy, V. Luchangco, P. Martin, and M. Moir. Nonblocking memory management support for dynamic-sized data
882 structures. ACM Transactions on Computer Systems (TOCS), 23(2):146–196, 2005.
890 # Compare-And-Swap instructions return the old value, one can make use of this in order to avoid an additional memory
891 access (suggested by Cory Nelson).
892 # Adapt algorithms to be lockfree on architectures with load-linked/store-conditional instructions.