Expand description
Thread-safe hybrid reference counting pointers
Loosely based on the algorithm described in “Biased reference counting: minimizing atomic operations in garbage collection” by Jiho Choi et. al. but adapted to Rust’s type system and its lack of a managed runtime environment.
The type HybridRc<T, State> provides thread-safe shared ownership of a value of type T
allocated on the heap, just like std::sync::Arc<T> does. The main difference is that one
thread at a time can use non-atomic reference counting for better performance. That means that
HybridRc is especially suited for workloads where one thread accesses the shared value
significantly more often than others.
There a two variants of HybridRc:
HybridRc<T,Local>(type aliased asRc): very fast but only usable on one thread.HybridRc<T,Shared>(type aliased asArc): slower but universally usable.
Instances of both variants are convertible into each other. Especially, an Rc can always be
converted into an Arc using HybridRc::to_shared(&rc) or .into().
An Arc on the other hand can only be converted into an Rc using HybridRc::to_local(&arc)
or .try_into() if no other thread has Rcs for the same value. The thread holding Rcs to
a value is called the “owner thread”. Once all Rcs are dropped, the shared value becomes
ownerless again.
HybridRc is designed as a drop-in replacement for std::sync::Arc and std::rc::Rc, so except
for the conversion functionality outlined above the usage is similar to these and other smart
pointers.
§Thread Safety
HybridRc uses two separate reference counters - one modified non-atomically and one using
atomic operations - and keeps track of a owner thread that is allowed to modify the “local”
reference counter. This means that it is thread-safe, while one thread is exempted from
the disadvantage of atomic operations being more expensive than ordinary memory accesses.
§no_std Support
This crate provides limited support for no_std environments. In this mode Arc::to_local() and
Weak::upgrade_local() only succeed if no Rc exists on any thread, as threads cannot be
reliably identified without std.
To enable no_std mode, disable the default enabled std feature in Cargo.toml. A global
allocator is required.
[dependencies]
hybrid-rc = { version = "…", default-features = false }§Examples
Multiple threads need a reference to a shared value while one thread needs to clone references to the value significantly more often than the others.
use hybrid_rc::{Rc, Arc};
use std::thread;
use std::sync::mpsc::channel;
let local = Rc::new(SomeComplexType::new());
let (sender, receiver) = channel();
// Spawn of threads for multiple expensive computations
for i in 1..=4 {
let sender = sender.clone();
let shared = Rc::to_shared(&local);
thread::spawn(move || {
sender.send(expensive_computation(shared, i));
});
}
// Do something that needs single-thread reference counting
for i in 1..=1000 {
do_something(local.clone(), i);
}
// Collect expensive computation results
for i in 1..=4 {
println!("{:?}", receiver.recv().unwrap());
}A library wants to give library consumers flexibility for multithreading but also internally
have the performance of std::rc::Rc for e.g. a complex tree structure that is mutated on
the main thread.
use hybrid_rc::Rc;
use std::thread;
let reference = get_local_hybridrc_from_some_library();
let shared = Rc::to_shared(&reference);
// do the work in another thread
let worker = thread::spawn(move || {
do_something(&*shared);
});
// Do something useful with the library
worker.join()?;Modules§
Structs§
- Alloc
Error - The
AllocErrorerror indicates an allocation failure when usingtry_new()etc. - Hybrid
Rc - A hybrid reference-counting pointer.
- PinWeak
PinWeak<T>represents a non-owning reference to a pinned value managed by aPin<HybridRc<T, _>>.- Weak
Weak<T>represents a non-owning reference to a value managed by aHybridRc<T, _>. The value is accessed by callingupgrade()orupgrade_local()onWeak.
Enums§
- Upgrade
Error - An enumeration of possible errors when upgrading a
Weak.