pub struct HazardEpoch { /* fields omitted */ }
HazardEpoch
a practical implementation of Hazard Pointers
, which use global incremental
version to identify shared object to be reclaimed. Because of False sharing
,
a part of the member variables, might be frequently modified by different threads, are aligned
to 64 bytes.
To improve performance, HazardEpoch
can be allocated in stack directly, but it can't be
moved after calling any method. thread_waiting_threshold
means the maximum of the number of
shared objects to be reclaimed under one thread. min_version_cache_time_us
means the time
interval(microsecond) to update minimum version cache.
use rs_lockfree::hazard_epoch::HazardEpoch;
let h = unsafe { HazardEpoch::new_in_stack(64, 200000) };
let addr_h = &h as *const _ as usize;
assert_eq!(addr_h % 64, 0);
Alloc HazardEpoch
in heap. Usage is the same as new_in_stack
.
use rs_lockfree::hazard_epoch::HazardEpoch;
let h = HazardEpoch::new_in_heap(64, 200000);
let _addr_h = &h as *const _ as usize;
Return Self::new_in_stack(64, 200000)
Return Self::new_in_heap(64, 200000)
Reclaim all shared objects waiting to be reclaimed. It will be called when dropping HazardEpoch
.
use rs_lockfree::hazard_epoch::HazardEpoch;
use rs_lockfree::hazard_epoch::BaseHazardNode;
let mut h = HazardEpoch::new_in_heap(64, 200000);
let node = Box::into_raw(Box::new(BaseHazardNode::default()));
unsafe { h.add_node(node); }
unsafe { h.retire(); }
Reclaim all shared objects waiting to be reclaimed. node
can be any type as long as it implements
Trait HazardNodeT
. BaseHazardNode
is used to realize vtable
.
use rs_lockfree::hazard_epoch::HazardEpoch;
use rs_lockfree::hazard_epoch::{BaseHazardNode, HazardNodeT};
use std::cell::RefCell;
struct Node<'a, T> {
base: BaseHazardNode,
cnt: &'a RefCell<i32>,
v: T,
}
impl<'a, T> Drop for Node<'a, T> {
fn drop(&mut self) {
*self.cnt.borrow_mut() += 10;
}
}
impl<'a, T> HazardNodeT for Node<'a, T> {
fn get_base_hazard_node(&self) -> *mut BaseHazardNode {
&self.base as *const _ as *mut _
}
}
let cnt = RefCell::new(0);
let mut h = HazardEpoch::default_new_in_heap();
let node = Box::into_raw(Box::new(Node{
base: Default::default(),
cnt: &cnt,
v: 2333,
}));
unsafe { h.add_node(node); }
drop(h);
assert_eq!(*cnt.borrow(), 10);
Before accessing a shared object, call method acquire
to get the handle
of this operation.
use rs_lockfree::hazard_epoch::HazardEpoch;
use rs_lockfree::hazard_epoch::BaseHazardNode;
use rs_lockfree::error::Status;
let mut h = HazardEpoch::default_new_in_heap();
let node = Box::into_raw(Box::new(BaseHazardNode::default()));
let mut handle = 0;
assert_eq!(h.acquire(&mut handle), Status::Success);
let _o = unsafe { &(*node) };
unsafe { h.release(handle); }
After accessing a shared object, call method release
to trigger reclaiming. Usage is the
same as acquire
.
Atomic load count of shared objects waiting to be reclaimed.
Executes the destructor for this type. Read more