Skip to main content

RcuCell

Struct RcuCell 

Source
pub struct RcuCell<T> { /* private fields */ }
Expand description

A concurrent data structure that allows for safe, read-copy-update (RCU) style access to its value.

§Grace period serialization

Only one old value can be pending reclamation at a time (single ptr_counter_to_clear slot). If multiple writers call write concurrently while readers hold guards to old values, their grace periods are serialized. This is acceptable for read-heavy workloads but can cause writer stalls under heavy write contention with long-lived readers.

Implementations§

Source§

impl<T> RcuCell<T>

Source

pub fn new(value: T) -> Self

Creates a new RcuCell with the given initial value.

§Example
let rcu_cell = rcu_128::RcuCell::new(42);
Examples found in repository?
examples/example.rs (line 6)
5fn main() {
6    let x = rcu_128::RcuCell::new(0);
7    std::thread::scope(|s| {
8        s.spawn(|| {
9            for i in 0..40 {
10                let t = Instant::now();
11                if i < 20 {
12                    x.write(i);
13                } else {
14                    x.update(|v| v + 1);
15                }
16                println!("Update {i} used time: {:?}", t.elapsed());
17                sleep((t + Duration::from_millis(100)).duration_since(Instant::now()));
18            }
19        });
20        s.spawn(|| {
21            // Always has 4 guards alive
22            let mut guards = [x.read(), x.read(), x.read(), x.read()];
23            for idx in 0..400 {
24                let r = x.read();
25                println!("Read value: {}", *r);
26                guards[idx % 4] = r;
27                sleep(Duration::from_millis(10));
28            }
29        });
30    })
31}
Source

pub fn read(&self) -> RcuGuard<'_, T>

Provides read access to the value stored in the RcuCell.

This function returns an RcuGuard, which allows for safe, concurrent read access to the RcuCell’s value.

Once all RcuGuard instances referencing a particular value are dropped, the value can be safely released during an update or write.

§Example
let rcu_cell = rcu_128::RcuCell::new(42);
{
    let guard = rcu_cell.read();
    assert_eq!(*guard, 42);
}
Examples found in repository?
examples/example.rs (line 22)
5fn main() {
6    let x = rcu_128::RcuCell::new(0);
7    std::thread::scope(|s| {
8        s.spawn(|| {
9            for i in 0..40 {
10                let t = Instant::now();
11                if i < 20 {
12                    x.write(i);
13                } else {
14                    x.update(|v| v + 1);
15                }
16                println!("Update {i} used time: {:?}", t.elapsed());
17                sleep((t + Duration::from_millis(100)).duration_since(Instant::now()));
18            }
19        });
20        s.spawn(|| {
21            // Always has 4 guards alive
22            let mut guards = [x.read(), x.read(), x.read(), x.read()];
23            for idx in 0..400 {
24                let r = x.read();
25                println!("Read value: {}", *r);
26                guards[idx % 4] = r;
27                sleep(Duration::from_millis(10));
28            }
29        });
30    })
31}
Source

pub fn write(&self, value: T)

Writes a new value into the RcuCell.

The new value becomes immediately visible to subsequent readers. This method blocks until all readers of the old value have dropped their guards, then frees the old value.

Multiple concurrent write calls are allowed (last-writer-wins). Use update if you need read-modify-write semantics.

§Example
let rcu_cell = rcu_128::RcuCell::new(42);
rcu_cell.write(100);
{
    let guard = rcu_cell.read();
    assert_eq!(*guard, 100);
}
Examples found in repository?
examples/example.rs (line 12)
5fn main() {
6    let x = rcu_128::RcuCell::new(0);
7    std::thread::scope(|s| {
8        s.spawn(|| {
9            for i in 0..40 {
10                let t = Instant::now();
11                if i < 20 {
12                    x.write(i);
13                } else {
14                    x.update(|v| v + 1);
15                }
16                println!("Update {i} used time: {:?}", t.elapsed());
17                sleep((t + Duration::from_millis(100)).duration_since(Instant::now()));
18            }
19        });
20        s.spawn(|| {
21            // Always has 4 guards alive
22            let mut guards = [x.read(), x.read(), x.read(), x.read()];
23            for idx in 0..400 {
24                let r = x.read();
25                println!("Read value: {}", *r);
26                guards[idx % 4] = r;
27                sleep(Duration::from_millis(10));
28            }
29        });
30    })
31}
Source

pub fn update(&self, f: impl FnOnce(&T) -> T)

Updates the value stored in the RcuCell using a provided function.

This function applies the given closure f to the current value, replacing it with the returned value. The closure runs under an exclusive lock, so concurrent update and write calls are serialized — the closure is guaranteed to run exactly once.

§Example
let rcu_cell = rcu_128::RcuCell::new(42);
rcu_cell.update(|&old_value| old_value + 1);
{
    let guard = rcu_cell.read();
    assert_eq!(*guard, 43);
}
Examples found in repository?
examples/example.rs (line 14)
5fn main() {
6    let x = rcu_128::RcuCell::new(0);
7    std::thread::scope(|s| {
8        s.spawn(|| {
9            for i in 0..40 {
10                let t = Instant::now();
11                if i < 20 {
12                    x.write(i);
13                } else {
14                    x.update(|v| v + 1);
15                }
16                println!("Update {i} used time: {:?}", t.elapsed());
17                sleep((t + Duration::from_millis(100)).duration_since(Instant::now()));
18            }
19        });
20        s.spawn(|| {
21            // Always has 4 guards alive
22            let mut guards = [x.read(), x.read(), x.read(), x.read()];
23            for idx in 0..400 {
24                let r = x.read();
25                println!("Read value: {}", *r);
26                guards[idx % 4] = r;
27                sleep(Duration::from_millis(10));
28            }
29        });
30    })
31}

Trait Implementations§

Source§

impl<T: Debug> Debug for RcuCell<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Default> Default for RcuCell<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T> Drop for RcuCell<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<T> !Freeze for RcuCell<T>

§

impl<T> !RefUnwindSafe for RcuCell<T>

§

impl<T> Send for RcuCell<T>
where T: Send,

§

impl<T> Sync for RcuCell<T>
where T: Sync,

§

impl<T> Unpin for RcuCell<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for RcuCell<T>

§

impl<T> UnwindSafe for RcuCell<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.