A naive RCU in Rust v0.1u1

Use RefCell and update the content in a mutex lock guard.

The content is wrapped in Arc so that readers can access concurrently.

The RefCell is wrapped in Mutex so the update can happen in a writer thread concurrently to active readers.

Arc makes sure the old resource is released after all old readers are done.

(Updated to use borrow() instead of get_mut() as suggested by Mihnea Stefan Popeanga.)

Code:

use std::thread;
use std::sync::{Arc, Mutex};
use std::cell::RefCell;
use std::time;

struct Rcu<T> {
    data: Mutex<RefCell<Arc<T>>>,
}

impl<T> Rcu<T> {
    fn new(t: T) -> Self {
        let cell = RefCell::new(Arc::new(t));
        let data = Mutex::new(cell);
        Self {
            data,
        }
    }
    fn write(&self, t: T) {
        let cell = self.data.lock().unwrap();
        cell.replace(Arc::new(t));
    }

    fn read(&self) -> Arc<T> {
        let cell = self.data.lock().unwrap();
        let r = cell.borrow().clone();
        r
    }
}

fn main() {
    struct MyStruct {
        generation: i32,
    }
    let data = Arc::new(Rcu::new(MyStruct {
        generation: 0,
    }));
    for i in 1..5 {
        let d = data.clone();
        thread::spawn(move || {
            loop {
                let ms = d.read();
                println!("read loop {}, generation: {}", i, ms.generation);
                thread::sleep(time::Duration::from_millis(100));
                println!("read loop {} doing some complex compuation on d...", i);
                thread::sleep(time::Duration::from_millis(100));
                println!("read loop {} done on generation {}...", i, ms.generation);
            }
        });
    }
    let d = data.clone();
    loop {
        println!("write loop");
        let ng = d.read().generation + 1;
        d.write(MyStruct {
            generation: ng,
        });
        thread::sleep(time::Duration::from_millis(1000));
    }
}

Test output:

Published by