In typical lock-free structure implementations, there are generally two aspects that need to be addressed:
Lock-free algorithm garbage collection is less related to data structures and application scenarios and is generally considered as a separate topic. For example, the article Performance of memory reclamation for lockless synchronization provides a review of some typical lock-free reclamation methods. It mentions several classic reclamation schemes: QSBR (Quiescent-state-based reclamation), EBR (Epoch-based reclamation), and HPBR (Hazard-pointer-based reclamation).
Epoch is a modified implementation of the EBR mechanism, which focuses on reducing the overhead caused by mechanisms through the separation of access, elimination, and reclamation actions. The main differences are:
#include "babylon/concurrent/epoch.h"
using ::babylon::Epoch;
// Define an Epoch instance
Epoch epoch;
// Use Epoch to open a thread-local critical section before accessing the shared structure
{
std::lock_guard<Epoch> lock {epoch};
... // Elements of the shared structure can be accessed within the critical section
} // After the critical section ends, the obtained element pointer can no longer be used
// In addition to thread-local mode, an Accessor can also be actively created to track the critical section
auto accessor = epoch.create_accessor();
{
std::lock_guard<Accessor> lock {accessor};
... // Elements of the shared structure can be accessed within the critical section
} // After the critical section ends, the obtained element pointer can no longer be used
{
accessor.lock();
Task task {::std::move(accessor), ...} // The critical section can be transferred by moving the accessor
... // It can be transferred to an asynchronous thread, etc. The critical section ends after accessor.unlock()
} // If transferred, the critical section will not end here
// Elimination operation
... // Operate on the shared structure, removing some elements
// Advance the epoch and return the minimum epoch at which the previously removed elements can be reclaimed
auto lowest_epoch = epoch.tick();
// The lowest_epoch is associated with the eliminated elements, which can be synchronously or asynchronously checked for actual reclamation
auto low_water_mark = epoch.low_water_mark();
// When low_water_mark exceeds lowest_epoch, the elements can be safely reclaimed
if (lowest_epoch <= low_water_mark) {
... // Elements corresponding to lowest_epoch can be reclaimed
}