Home > other >  Read and Write the same variable in multiple threads in Rust
Read and Write the same variable in multiple threads in Rust

Time:11-07

I'm doing a simple program to simulate a supermarket queue to learn Rust. The program consists in two threads. One is adding people (char 'x') to the supermarket queue and the other one is removing them.

I use Arc and Mutex to handle the concurrency but it seems that the first thread never free the var, so the second doesn't work.

The code is the follows:

let queue = Arc::new(Mutex::new(Vec::<char>::new()));

let queue1 = Arc::clone(&queue);
    thread::spawn(move || loop {
        let mut aux = queue1.lock().unwrap();
        aux.push('x');
        print_queue(&aux);
        thread::sleep(Duration::from_secs(3));
    });

thread::spawn(move || loop {
        let mut aux = queue.lock().unwrap();
        println!("AUX state: {:?}", aux);
        if !&aux.is_empty() {
            aux.pop();
        }
        print_queue(&aux);
        let mut rng = rand::thread_rng();
        thread::sleep(Duration::from_secs(rng.gen_range(1..10)));
    });

The print of the AUX state never shows. What I'm doing wrong?

CodePudding user response:

Your code is using this pattern:

loop {
    let mut guard = mutex.lock().unwrap();
    // do something with `guard`

    thread::sleep(duration);

    // `guard` is implicitly dropped at the end of the scope
}

The problem with this code is that the mutex guard (in this case guard) holds the lock, and it holds it until it is dropped, which in this case happens when the variable goes out of scope. But it goes out of scope after the thread is sleeping, so the thread will still hold the lock while it sleeps.

To avoid this, you should drop the guard immediately once you're done using it, before the thread sleeps:

loop {
    {
        let mut guard = mutex.lock().unwrap();
        // do something with `guard`
        
        // implicitly drop `guard` at the end of the inner scope, before sleep
    }
    thread::sleep(duration);
}

or

loop {
    let mut guard = mutex.lock().unwrap();
    // do something with `guard`

    // explicitly drop `guard` before sleep
    drop(guard);

    thread::sleep(duration);
}
  • Related