0

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?

1
  • Can you give a reproducible example? Also, this sounds a better fit for a channel. Commented Nov 6, 2022 at 13:09

1 Answer 1

1

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much!!! The explanation is very clear and it works perfectly!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.