3 #ifndef __CDS_INTRUSIVE_DETAILS_BASE_H
4 #define __CDS_INTRUSIVE_DETAILS_BASE_H
6 #include <cds/intrusive/details/node_traits.h>
7 #include <cds/details/allocator.h>
8 #include <cds/algo/backoff_strategy.h>
12 /// Intrusive containers
14 @ingroup cds_intrusive_containers
15 The namespace cds::intrusive contains intrusive lock-free containers.
16 The idea comes from \p boost::intrusive library, see http://boost.org/doc/ as a good introduction to intrusive approach.
17 The intrusive containers of libcds library is developed as close to \p boost::intrusive
19 In terms of lock-free approach, the main advantage of intrusive containers is
20 that no memory allocation is performed to maintain container items.
21 However, additional requirements is imposed for types and values that can be stored in intrusive container.
22 See the container documentation for details.
24 \anchor cds_intrusive_hook_tag
26 Many hooks and nodes for intrusive containers contain template argument \p Tag.
27 This argument serves as a tag, so you can derive from more than one container's node and hence put an object in multiple intrusive containers
28 at the same time. An incomplete type can serve as a tag. If you specify two hooks, you must specify a different tag for each one.
32 cds::intrusive::treiber_stack::node< cds::gc::HP, tag<tag1> >
34 If no tag is specified åðó default \p cds::opt::none will be used.
36 \anchor cds_intrusive_item_destroying
39 It should be very careful when destroying an item removed from intrusive container.
40 In other threads the references to popped item may exists some time after removing.
41 To destroy the removed item in thread-safe manner you should call static function \p retire
42 of garbage collector you use, for example:
45 void operator ()( my_type * p )
51 typedef cds::intrusive::TreiberStack< cds::gc::HP, my_type, cds::opt::disposer< destroyer > > stack;
56 my_type * p = s.pop();
63 cds::gc:HP::retire< destroyer >( p );
66 The situation becomes even more complicated when you want store items in different intrusive containers.
67 In this case the best way is using reference counting:
71 std::atomic<unsigned int> nRefCount;
79 void operator ()( my_type * p )
81 if ( --p->nRefCount == 0 )
82 delete p ; // delete only after no reference pointing to p
86 typedef cds::intrusive::TreiberStack< cds::gc::HP, my_type, cds::opt::disposer< destroyer > > stack;
87 typedef cds::intrusive::MSQueue< cds::gc::HP, my_type, cds::opt::disposer< destroyer > > queue;
91 my_type * v = new my_type();
93 v.nRefCount++ ; // increment counter before pushing the item to the stack
96 v.nRefCount++ ; // increment counter before pushing the item to the queue
101 my_type * ps = s.pop();
107 cds::gc:HP::retire< destroyer >( ps );
110 my_type * pq = q.pop();
116 cds::gc:HP::retire< destroyer >( pq );
119 Violation of these rules may lead to a crash.
121 \par Intrusive containers and Hazard Pointer-like garbage collectors
123 If you develop your intrusive container based on <b>libcds</b> library framework, you should
124 take in the account the following.
125 The main idea of garbage collectors (GC) based on Hazard Pointer schema is protecting a shared pointer
126 by publishing it as a "hazard" one i.e. as a pointer that is changing at the current time and cannot be
127 deleted at this moment. In intrusive container paradigm, the pointer to the node of the container
128 and the pointer to the item stored in the container are not equal in the general case.
129 However, any pointer to the node should be castable to the appropriate pointer to the container's item.
130 In general, any item can be placed to some different intrusive containers simultaneously,
131 and each of those container holds a unique pointer to its node that refers to the same item.
132 When we protect a pointer, we want to protect an <b>item</b> pointer that is the invariant
133 for any container stored that item. In your intrusive container, instead of protecting by GC's guard a pointer to an node
134 you should convert it to the pointer to the item and then protect resulting item pointer.
135 Otherwise an unpredictable result may occur.
137 namespace intrusive {
139 /// @defgroup cds_intrusive_containers Intrusive containers
140 /** @defgroup cds_intrusive_helper Helper structs for intrusive containers
141 @ingroup cds_intrusive_containers
143 /** @defgroup cds_intrusive_stack Stack
144 @ingroup cds_intrusive_containers
146 /** @defgroup cds_intrusive_queue Queue
147 @ingroup cds_intrusive_containers
149 /** @defgroup cds_intrusive_priority_queue Priority queue
150 @ingroup cds_intrusive_containers
152 /** @defgroup cds_intrusive_deque Deque
153 @ingroup cds_intrusive_containers
155 /** @defgroup cds_intrusive_map Set
156 @ingroup cds_intrusive_containers
158 /** @defgroup cds_intrusive_tree Tree
159 @ingroup cds_intrusive_containers
161 /** @defgroup cds_intrusive_list List
162 @ingroup cds_intrusive_containers
165 }} // namespace cds::intrusuve
167 #endif // #ifndef __CDS_INTRUSIVE_DETAILS_BASE_H