rustreadwritelock

How to create a vector of RwLock in rust?


I need to make a vector of struct. Each element of the vector have to be protected by a RwLock. Threads need to read and write in this vector ( thanks to RwLock ). How can I do that in Rust.

I've tried using a vector of Arc.

#[derive(Default, Debug, Clone, Copy)]
pub struct shared_values {
    x: usize,
    y: usize,
}

fn main() {
    let mut shared = vec![Arc::new(RwLock::new(shared_values { x: 0, y: 0 })); 10];

    //changing value of the element [0]
    {
        let mut sh = shared[0].write().unwrap();
        *sh = shared_values { x: 10, y: 10 };
    }

    //Printing
    {
        println!("Print RwLock");
        for i in 0..g.ns {
            {
                let val = shared[i].read().unwrap();
                println!("{:?}", val);
            }
        }
    }
}

The result is like that :

RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }
RwLockReadGuard { lock: RwLock { data: shared_values { suitor: 10, ws: 10 } } }

I expected the element 0 to be set with { x : 10, y : 10 }

I think Arc increase the counting reference of shared_values { x : 0 , y : 0 } but doesn't create an independant element for each index in the vector.


Solution

  • This vector initialization clones the parameter. Use std::iter::repeat_with:

    use std::sync::{Arc, RwLock};
    
    #[derive(Default, Debug, Clone, Copy)]
    pub struct SharedValues {
        x: usize,
        y: usize,
    }
    
    fn main() {
        let shared: Vec<_> =
            std::iter::repeat_with(|| Arc::new(RwLock::new(SharedValues { x: 0, y: 0 })))
                .take(10)
                .collect();
    
        //changing value of the element [0]
        {
            let mut sh = shared[0].write().unwrap();
            *sh = SharedValues { x: 10, y: 10 };
        }
    
        //Printing
        {
            println!("Print RwLock");
            for x in shared {
                println!("{:?}", x.read().unwrap());
            }
        }
    }
    

    If you miss the simplicity of a macro, you can write your own:

    macro_rules! vec_no_clone {
        ( $val:expr; $n:expr ) => {{
            let result: Vec<_> = std::iter::repeat_with(|| $val).take($n).collect();
            result
        }};
    }
    
    fn main() {
        let shared = vec_no_clone![Arc::new(RwLock::new(SharedValues { x: 0, y: 0 })); 10];
    }