2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef CDSLIB_GC_IMPL_HP_DECL_H
32 #define CDSLIB_GC_IMPL_HP_DECL_H
34 #include <stdexcept> // overflow_error
35 #include <cds/gc/details/hp.h>
36 #include <cds/details/marked_ptr.h>
38 namespace cds { namespace gc {
39 /// @defgroup cds_garbage_collector Garbage collectors
41 /// Hazard Pointer garbage collector
42 /** @ingroup cds_garbage_collector
43 @headerfile cds/gc/hp.h
45 Implementation of classic Hazard Pointer garbage collector.
48 - [2002] Maged M.Michael "Safe memory reclamation for dynamic lock-freeobjects using atomic reads and writes"
49 - [2003] Maged M.Michael "Hazard Pointers: Safe memory reclamation for lock-free objects"
50 - [2004] Andrei Alexandrescy, Maged Michael "Lock-free Data Structures with Hazard Pointers"
52 Hazard Pointer garbage collector is a singleton. The main user-level part of Hazard Pointer schema is
53 GC class \p %cds::gc::HP and its nested classes. Before use any HP-related class you must initialize HP garbage collector
54 by contructing \p %cds::gc::HP object in beginning of your \p main().
55 See \ref cds_how_to_use "How to use" section for details how to apply garbage collector.
60 /// Native guarded pointer type
62 @headerfile cds/gc/hp.h
64 typedef gc::hp::hazard_pointer guarded_pointer;
68 @headerfile cds/gc/hp.h
70 template <typename T> using atomic_ref = atomics::atomic<T *>;
72 /// Atomic marked pointer
74 @headerfile cds/gc/hp.h
76 template <typename MarkedPtr> using atomic_marked_ptr = atomics::atomic<MarkedPtr>;
80 @headerfile cds/gc/hp.h
82 template <typename T> using atomic_type = atomics::atomic<T>;
84 /// Thread GC implementation for internal usage
86 @headerfile cds/gc/hp.h
88 typedef hp::ThreadGC thread_gc_impl;
90 /// Exception "Too many Hazard Pointer"
91 typedef hp::GarbageCollector::too_many_hazard_ptr too_many_hazard_ptr_exception;
93 /// Wrapper for hp::ThreadGC class
95 @headerfile cds/gc/hp.h
96 This class performs automatically attaching/detaching Hazard Pointer GC
97 for the current thread.
99 class thread_gc: public thread_gc_impl
108 The constructor attaches the current thread to the Hazard Pointer GC
109 if it is not yet attached.
110 The \p bPersistent parameter specifies attachment persistence:
111 - \p true - the class destructor will not detach the thread from Hazard Pointer GC.
112 - \p false (default) - the class destructor will detach the thread from Hazard Pointer GC.
115 bool bPersistent = false
116 ) ; //inline in hp_impl.h
120 If the object has been created in persistent mode, the destructor does nothing.
121 Otherwise it detaches the current thread from Hazard Pointer GC.
123 ~thread_gc() ; // inline in hp_impl.h
125 public: // for internal use only!!!
127 static cds::gc::hp::details::hp_guard* alloc_guard(); // inline in hp_impl.h
128 static void free_guard( cds::gc::hp::details::hp_guard* g ); // inline in hp_impl.h
132 /// Hazard Pointer guard
134 @headerfile cds/gc/hp.h
136 A guard is a hazard pointer.
137 Additionally, the \p %Guard class manages allocation and deallocation of the hazard pointer.
139 \p %Guard object is movable but not copyable.
141 The guard object can be in two states:
142 - unlinked - the guard is not linked with any internal hazard pointer.
143 In this state no operation except \p link() and move assignment is supported.
144 - linked (default) - the guard allocates an internal hazard pointer and fully operable.
146 Due to performance reason the implementation does not check state of the guard in runtime.
148 @warning Move assignment can transfer the guard in unlinked state, use with care.
153 /// Default ctor allocates a guard (hazard pointer) from thread-private storage
155 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
157 Guard(); // inline in hp_impl.h
159 /// Initilalizes an unlinked guard i.e. the guard contains no hazard pointer. Used for move semantics support
160 explicit Guard( std::nullptr_t ) CDS_NOEXCEPT
164 /// Move ctor - \p src guard becomes unlinked (transfer internal guard ownership)
165 Guard( Guard&& src ) CDS_NOEXCEPT
166 : m_guard( src.m_guard )
168 src.m_guard = nullptr;
171 /// Move assignment: the internal guards are swapped between \p src and \p this
173 @warning \p src will become in unlinked state if \p this was unlinked on entry.
175 Guard& operator=( Guard&& src ) CDS_NOEXCEPT
177 std::swap( m_guard, src.m_guard );
181 /// Copy ctor is prohibited - the guard is not copyable
182 Guard( Guard const& ) = delete;
184 /// Copy assignment is prohibited
185 Guard& operator=( Guard const& ) = delete;
187 /// Frees the internal hazard pointer if the guard is in linked state
193 /// Checks if the guard object linked with any internal hazard pointer
194 bool is_linked() const
196 return m_guard != nullptr;
199 /// Links the guard with internal hazard pointer if the guard is in unlinked state
201 @warning Can throw \p too_many_hazard_ptr_exception if internal hazard pointer objects are exhausted.
203 void link(); // inline in hp_impl.h
205 /// Unlinks the guard from internal hazard pointer; the guard becomes in unlinked state
206 void unlink(); // inline in hp_impl.h
208 /// Protects a pointer of type \p atomic<T*>
210 Return the value of \p toGuard
212 The function tries to load \p toGuard and to store it
213 to the HP slot repeatedly until the guard's value equals \p toGuard
215 @warning The guad object should be in linked state, otherwise the result is undefined
217 template <typename T>
218 T protect( atomics::atomic<T> const& toGuard )
220 assert( m_guard != nullptr );
222 T pCur = toGuard.load(atomics::memory_order_acquire);
225 pRet = assign( pCur );
226 pCur = toGuard.load(atomics::memory_order_acquire);
227 } while ( pRet != pCur );
231 /// Protects a converted pointer of type \p atomic<T*>
233 Return the value of \p toGuard
235 The function tries to load \p toGuard and to store result of \p f functor
236 to the HP slot repeatedly until the guard's value equals \p toGuard.
238 The function is useful for intrusive containers when \p toGuard is a node pointer
239 that should be converted to a pointer to the value before protecting.
240 The parameter \p f of type Func is a functor that makes this conversion:
243 value_type * operator()( T * p );
246 Actually, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
248 @warning The guad object should be in linked state, otherwise the result is undefined
250 template <typename T, class Func>
251 T protect( atomics::atomic<T> const& toGuard, Func f )
253 assert( m_guard != nullptr );
255 T pCur = toGuard.load(atomics::memory_order_acquire);
260 pCur = toGuard.load(atomics::memory_order_acquire);
261 } while ( pRet != pCur );
265 /// Store \p p to the guard
267 The function equals to a simple assignment the value \p p to guard, no loop is performed.
268 Can be used for a pointer that cannot be changed concurrently
270 @warning The guad object should be in linked state, otherwise the result is undefined
272 template <typename T>
273 T * assign( T* p ); // inline in hp_impl.h
276 std::nullptr_t assign( std::nullptr_t )
278 assert(m_guard != nullptr );
279 return *m_guard = nullptr;
283 /// Copy a value guarded from \p src guard to \p this guard (valid only in linked state)
284 void copy( Guard const& src )
286 assign( src.get_native() );
289 /// Store marked pointer \p p to the guard
291 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
292 Can be used for a marked pointer that cannot be changed concurrently.
294 @warning The guad object should be in linked state, otherwise the result is undefined
296 template <typename T, int BITMASK>
297 T * assign( cds::details::marked_ptr<T, BITMASK> p )
299 return assign( p.ptr());
302 /// Clear value of the guard (valid only in linked state)
308 /// Get the value currently protected (valid only in linked state)
309 template <typename T>
312 return reinterpret_cast<T *>( get_native() );
315 /// Get native hazard pointer stored (valid only in linked state)
316 guarded_pointer get_native() const
318 assert( m_guard != nullptr );
319 return m_guard->get();
323 hp::details::hp_guard* release()
325 hp::details::hp_guard* g = m_guard;
333 hp::details::hp_guard* m_guard;
337 /// Array of Hazard Pointer guards
339 @headerfile cds/gc/hp.h
340 The class is intended for allocating an array of hazard pointer guards.
341 Template parameter \p Count defines the size of the array.
344 template <size_t Count>
348 /// Rebind array for other size \p Count2
349 template <size_t Count2>
351 typedef GuardArray<Count2> other; ///< rebinding result
355 static CDS_CONSTEXPR const size_t c_nCapacity = Count;
358 /// Default ctor allocates \p Count hazard pointers
359 GuardArray(); // inline in hp_impl.h
361 /// Move ctor is prohibited
362 GuardArray( GuardArray&& ) = delete;
364 /// Move assignment is prohibited
365 GuardArray& operator=( GuardArray&& ) = delete;
367 /// Copy ctor is prohibited
368 GuardArray( GuardArray const& ) = delete;
370 /// Copy assignment is prohibited
371 GuardArray& operator=( GuardArray const& ) = delete;
373 /// Frees allocated hazard pointers
374 ~GuardArray(); // inline in hp_impl.h
376 /// Protects a pointer of type \p atomic<T*>
378 Return the value of \p toGuard
380 The function tries to load \p toGuard and to store it
381 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
383 template <typename T>
384 T protect( size_t nIndex, atomics::atomic<T> const& toGuard )
386 assert( nIndex < capacity());
390 pRet = assign( nIndex, toGuard.load(atomics::memory_order_acquire) );
391 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
396 /// Protects a pointer of type \p atomic<T*>
398 Return the value of \p toGuard
400 The function tries to load \p toGuard and to store it
401 to the slot \p nIndex repeatedly until the guard's value equals \p toGuard
403 The function is useful for intrusive containers when \p toGuard is a node pointer
404 that should be converted to a pointer to the value type before guarding.
405 The parameter \p f of type Func is a functor that makes this conversion:
408 value_type * operator()( T * p );
411 Really, the result of <tt> f( toGuard.load() ) </tt> is assigned to the hazard pointer.
413 template <typename T, class Func>
414 T protect( size_t nIndex, atomics::atomic<T> const& toGuard, Func f )
416 assert( nIndex < capacity() );
420 assign( nIndex, f( pRet = toGuard.load(atomics::memory_order_acquire) ));
421 } while ( pRet != toGuard.load(atomics::memory_order_acquire));
426 /// Store \p to the slot \p nIndex
428 The function equals to a simple assignment, no loop is performed.
430 template <typename T>
431 T * assign( size_t nIndex, T * p ); // inline in hp_impl.h
433 /// Store marked pointer \p p to the guard
435 The function equals to a simple assignment of <tt>p.ptr()</tt>, no loop is performed.
436 Can be used for a marked pointer that cannot be changed concurrently.
438 template <typename T, int BITMASK>
439 T * assign( size_t nIndex, cds::details::marked_ptr<T, BITMASK> p )
441 return assign( nIndex, p.ptr() );
444 /// Copy guarded value from \p src guard to slot at index \p nIndex
445 void copy( size_t nIndex, Guard const& src )
447 assign( nIndex, src.get_native() );
450 /// Copy guarded value from slot \p nSrcIndex to slot at index \p nDestIndex
451 void copy( size_t nDestIndex, size_t nSrcIndex )
453 assign( nDestIndex, get_native( nSrcIndex ));
456 /// Clear value of the slot \p nIndex
457 void clear( size_t nIndex )
459 m_arr.clear( nIndex );
462 /// Get current value of slot \p nIndex
463 template <typename T>
464 T * get( size_t nIndex ) const
466 return reinterpret_cast<T *>( get_native( nIndex ) );
469 /// Get native hazard pointer stored
470 guarded_pointer get_native( size_t nIndex ) const
472 assert( nIndex < capacity() );
473 return m_arr[nIndex]->get();
477 hp::details::hp_guard* release( size_t nIndex ) CDS_NOEXCEPT
479 return m_arr.release( nIndex );
483 /// Capacity of the guard array
484 static CDS_CONSTEXPR size_t capacity()
491 hp::details::hp_array<Count> m_arr;
497 A guarded pointer is a pair of a pointer and GC's guard.
498 Usually, it is used for returning a pointer to the item from an lock-free container.
499 The guard prevents the pointer to be early disposed (freed) by GC.
500 After destructing \p %guarded_ptr object the pointer can be disposed (freed) automatically at any time.
503 - \p GuardedType - a type which the guard stores
504 - \p ValueType - a value type
505 - \p Cast - a functor for converting <tt>GuardedType*</tt> to <tt>ValueType*</tt>. Default is \p void (no casting).
507 For intrusive containers, \p GuardedType is the same as \p ValueType and no casting is needed.
508 In such case the \p %guarded_ptr is:
510 typedef cds::gc::HP::guarded_ptr< foo > intrusive_guarded_ptr;
513 For standard (non-intrusive) containers \p GuardedType is not the same as \p ValueType and casting is needed.
521 struct value_accessor {
522 std::string* operator()( foo* pFoo ) const
524 return &(pFoo->value);
529 typedef cds::gc::HP::guarded_ptr< Foo, std::string, value_accessor > nonintrusive_guarded_ptr;
532 You don't need use this class directly.
533 All set/map container classes from \p libcds declare the typedef for \p %guarded_ptr with appropriate casting functor.
535 template <typename GuardedType, typename ValueType=GuardedType, typename Cast=void >
539 struct trivial_cast {
540 ValueType * operator()( GuardedType * p ) const
546 template <typename GT, typename VT, typename C> friend class guarded_ptr;
550 typedef GuardedType guarded_type; ///< Guarded type
551 typedef ValueType value_type; ///< Value type
553 /// Functor for casting \p guarded_type to \p value_type
554 typedef typename std::conditional< std::is_same<Cast, void>::value, trivial_cast, Cast >::type value_cast;
557 /// Creates empty guarded pointer
558 guarded_ptr() CDS_NOEXCEPT
563 explicit guarded_ptr( hp::details::hp_guard* g ) CDS_NOEXCEPT
567 /// Initializes guarded pointer with \p p
568 explicit guarded_ptr( guarded_type* p ) CDS_NOEXCEPT
569 : m_pGuard( nullptr )
573 explicit guarded_ptr( std::nullptr_t ) CDS_NOEXCEPT
574 : m_pGuard( nullptr )
579 guarded_ptr( guarded_ptr&& gp ) CDS_NOEXCEPT
580 : m_pGuard( gp.m_pGuard )
582 gp.m_pGuard = nullptr;
586 template <typename GT, typename VT, typename C>
587 guarded_ptr( guarded_ptr<GT, VT, C>&& gp ) CDS_NOEXCEPT
588 : m_pGuard( gp.m_pGuard )
590 gp.m_pGuard = nullptr;
593 /// Ctor from \p Guard
594 explicit guarded_ptr( Guard&& g ) CDS_NOEXCEPT
595 : m_pGuard( g.release() )
598 /// The guarded pointer is not copy-constructible
599 guarded_ptr( guarded_ptr const& gp ) = delete;
601 /// Clears the guarded pointer
603 \ref release() is called if guarded pointer is not \ref empty()
605 ~guarded_ptr() CDS_NOEXCEPT
610 /// Move-assignment operator
611 guarded_ptr& operator=( guarded_ptr&& gp ) CDS_NOEXCEPT
613 std::swap( m_pGuard, gp.m_pGuard );
617 /// Move-assignment from \p Guard
618 guarded_ptr& operator=( Guard&& g ) CDS_NOEXCEPT
620 std::swap( m_pGuard, g.m_guard );
624 /// The guarded pointer is not copy-assignable
625 guarded_ptr& operator=(guarded_ptr const& gp) = delete;
627 /// Returns a pointer to guarded value
628 value_type * operator ->() const CDS_NOEXCEPT
631 return value_cast()( reinterpret_cast<guarded_type *>(m_pGuard->get()));
634 /// Returns a reference to guarded value
635 value_type& operator *() CDS_NOEXCEPT
638 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
641 /// Returns const reference to guarded value
642 value_type const& operator *() const CDS_NOEXCEPT
645 return *value_cast()(reinterpret_cast<guarded_type *>(m_pGuard->get()));
648 /// Checks if the guarded pointer is \p nullptr
649 bool empty() const CDS_NOEXCEPT
651 return !m_pGuard || m_pGuard->get( atomics::memory_order_relaxed ) == nullptr;
654 /// \p bool operator returns <tt>!empty()</tt>
655 explicit operator bool() const CDS_NOEXCEPT
660 /// Clears guarded pointer
662 If the guarded pointer has been released, the pointer can be disposed (freed) at any time.
663 Dereferncing the guarded pointer after \p release() is dangerous.
665 void release() CDS_NOEXCEPT
671 // For internal use only!!!
672 void reset(guarded_type * p) CDS_NOEXCEPT
685 m_pGuard = thread_gc::alloc_guard();
691 thread_gc::free_guard( m_pGuard );
699 hp::details::hp_guard* m_pGuard;
705 enum class scan_type {
706 classic = hp::classic, ///< classic scan as described in Michael's papers
707 inplace = hp::inplace ///< inplace scan without allocation
709 /// Initializes %HP singleton
711 The constructor initializes GC singleton with passed parameters.
712 If GC instance is not exist then the function creates the instance.
713 Otherwise it does nothing.
715 The Michael's %HP reclamation schema depends of three parameters:
716 - \p nHazardPtrCount - hazard pointer count per thread. Usually it is small number (up to 10) depending from
717 the data structure algorithms. By default, if \p nHazardPtrCount = 0, the function
718 uses maximum of the hazard pointer count for CDS library.
719 - \p nMaxThreadCount - max count of thread with using Hazard Pointer GC in your application. Default is 100.
720 - \p nMaxRetiredPtrCount - capacity of array of retired pointers for each thread. Must be greater than
721 <tt> nHazardPtrCount * nMaxThreadCount </tt>. Default is <tt>2 * nHazardPtrCount * nMaxThreadCount </tt>.
724 size_t nHazardPtrCount = 0, ///< Hazard pointer count per thread
725 size_t nMaxThreadCount = 0, ///< Max count of simultaneous working thread in your application
726 size_t nMaxRetiredPtrCount = 0, ///< Capacity of the array of retired objects for the thread
727 scan_type nScanType = scan_type::inplace ///< Scan type (see \p scan_type enum)
730 hp::GarbageCollector::Construct(
734 static_cast<hp::scan_type>(nScanType)
738 /// Terminates GC singleton
740 The destructor destroys %HP global object. After calling of this function you may \b NOT
741 use CDS data structures based on \p %cds::gc::HP.
742 Usually, %HP object is destroyed at the end of your \p main().
746 hp::GarbageCollector::Destruct( true );
749 /// Checks if count of hazard pointer is no less than \p nCountNeeded
751 If \p bRaiseException is \p true (that is the default), the function raises
752 an \p std::overflow_error exception "Too few hazard pointers"
753 if \p nCountNeeded is more than the count of hazard pointer per thread.
755 static bool check_available_guards( size_t nCountNeeded, bool bRaiseException = true )
757 if ( hp::GarbageCollector::instance().getHazardPointerCount() < nCountNeeded ) {
758 if ( bRaiseException )
759 throw std::overflow_error( "Too few hazard pointers" );
765 /// Returns max Hazard Pointer count
766 static size_t max_hazard_count()
768 return hp::GarbageCollector::instance().getHazardPointerCount();
771 /// Returns max count of thread
772 static size_t max_thread_count()
774 return hp::GarbageCollector::instance().getMaxThreadCount();
777 /// Returns capacity of retired pointer array
778 static size_t retired_array_capacity()
780 return hp::GarbageCollector::instance().getMaxRetiredPtrCount();
783 /// Retire pointer \p p with function \p pFunc
785 The function places pointer \p p to array of pointers ready for removing.
786 (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
787 Deleting the pointer is the function \p pFunc call.
789 template <typename T>
790 static void retire( T * p, void (* pFunc)(T *) ); // inline in hp_impl.h
792 /// Retire pointer \p p with functor of type \p Disposer
794 The function places pointer \p p to array of pointers ready for removing.
795 (so called retired pointer array). The pointer can be safely removed when no hazard pointer points to it.
797 Deleting the pointer is an invocation of some object of type \p Disposer; the interface of \p Disposer is:
799 template <typename T>
801 void operator()( T * p ) ; // disposing operator
804 Since the functor call can happen at any time after \p retire call, additional restrictions are imposed to \p Disposer type:
805 - it should be stateless functor
806 - it should be default-constructible
807 - the result of functor call with argument \p p should not depend on where the functor will be called.
810 Operator \p delete functor:
812 template <typename T>
814 void operator ()( T * p ) {
819 // How to call GC::retire method
822 // ... use p in lock-free manner
824 cds::gc::HP::retire<disposer>( p ) ; // place p to retired pointer array of HP GC
827 Functor based on \p std::allocator :
829 template <typename ALLOC = std::allocator<int> >
831 template <typename T>
832 void operator()( T * p ) {
833 typedef typename ALLOC::templare rebind<T>::other alloc_t;
836 a.deallocate( p, 1 );
841 template <class Disposer, typename T>
842 static void retire( T * p ); // inline in hp_impl.h
844 /// Get current scan strategy
845 static scan_type getScanType()
847 return static_cast<scan_type>( hp::GarbageCollector::instance().getScanType());
850 /// Set current scan strategy
851 static void setScanType(
852 scan_type nScanType ///< new scan strategy
855 hp::GarbageCollector::instance().setScanType( static_cast<hp::scan_type>(nScanType) );
858 /// Checks if Hazard Pointer GC is constructed and may be used
861 return hp::GarbageCollector::isUsed();
864 /// Forced GC cycle call for current thread
866 Usually, this function should not be called directly.
868 static void scan() ; // inline in hp_impl.h
870 /// Synonym for \ref scan()
871 static void force_dispose()
876 }} // namespace cds::gc
878 #endif // #ifndef CDSLIB_GC_IMPL_HP_DECL_H