Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do I use to share an object with many threads and one writer in Rust?

Tags:

rust

What is the right approach to share a common object between many threads when the object may sometimes be written to by one owner?

I tried to create one Configuration trait object with several methods to get and set config keys. I'd like to pass this to other threads where configuration items may be read. Bonus points would be if it can be written and read by everyone.

I found a Reddit thread which talks about Rc and RefCell; would that be the right way? I think these would not allow me to borrow the object immutably multiple times and still mutate it.

like image 326
buster Avatar asked Dec 19 '22 08:12

buster


1 Answers

Rust has a built-in concurrency primitive exactly for this task called RwLock. Together with Arc, it can be used to implement what you want:

use std::sync::{Arc, RwLock};
use std::sync::mpsc;
use std::thread;

const N: usize = 12;

let shared_data = Arc::new(RwLock::new(Vec::new()));
let (finished_tx, finished_rx) = mpsc::channel();

for i in 0..N {
    let shared_data = shared_data.clone();
    let finished_tx = finished_tx.clone();
    if i % 4 == 0 {
        thread::spawn(move || {
            let mut guard = shared_data.write().expect("Unable to lock");
            guard.push(i);
            finished_tx.send(()).expect("Unable to send");
        });
    } else {
        thread::spawn(move || {
            let guard = shared_data.read().expect("Unable to lock");
            println!("From {}: {:?}", i, *guard);
            finished_tx.send(()).expect("Unable to send");
        });
    }
}

// wait until everything's done
for _ in 0..N {
    let _ = finished_rx.recv();
}

println!("Done");

This example is very silly but it demonstrates what RwLock is and how to use it.

Also note that Rc and RefCell/Cell are not appropriate in a multithreaded environment because they are not synchronized properly. Rust won't even allow you to use them at all with thread::spawn(). To share data between threads you must use an Arc, and to share mutable data you must additionally use one of the synchronization primitives like RWLock or Mutex.

like image 124
Vladimir Matveev Avatar answered Dec 26 '22 00:12

Vladimir Matveev