Can't lock more than one element of vector of mutexes

Hi there, in my efforts to debug an application, I wanted to lock two mutexes that are in a vector of mutexes, however, the program blocks forever when trying to acquire the second lock

I must have an incorrect understanding how the language works as to why I'm messing up this badly, if anyone can explain why this doesn't work I'd be very thankful

let test_strips = vec![ Arc::new( Mutex::new( vec![0;1] ) ) ; 2];
let lock1 = test_strips[0].lock().unwrap();
println!("Locked 1");
let lock2 = test_strips[1].lock().unwrap();
println!("Locked 2"); //We never reach this 

drop(lock1);
drop(lock2);

Many thanks

vec![ Arc::new( Mutex::new( vec![0;1] ) ) ; 2];

This is the problem - initalizing a Vec like this creates two clones of the same Arc (which are both referencing the same data), so you're actually locking the same mutex twice. If you create two seperate mutexes and then do vec![mutex1, mutex2], it should work.

3 Likes

The vec![x; n] macro creates many clones of a single element, it doesn’t re-evaluate the expression multiple times. Hence both your Arcs point to the same mutex.

To fix this, initialize it e.g. with

let test_strips: Vec<_> = std::iter::repeat_with(|| Arc::new( Mutex::new( vec![0;1] ))).take(2).collect();
1 Like

Oo right I see, thank you very much for the instant reply :smiley:

What is this take() method used for

iter::repeat_with(|| …) creates an infinite iterator whose elements are created by evaluating the given closure. The .take(n) method turns it into an iterator of length n. Finally, collect(), collects those n items into a vector.

Following this post (provided nothing changed in the meantime), this is one of two reasonable (yet unfortunately still somewhat verbose) alternative approaches to produce a Vec of n elements generated by some given closure; the other way involves using Vec::resize_with.

5 Likes

If it is 2, will vec! storage be like this?

vec![Arc<Mutex<1>>,  Arc<Mutex<2>>]

Yeah, for 2 you could reasonably and equivalently write it as

let test_strips = vec![Arc::new( Mutex::new( vec![0;1] )), Arc::new( Mutex::new( vec![0;1] ))];

as well.


Essentially, something like

let v = vec![f(); 3];

behaves essentially like

let x = f();
let v = vec![x.clone(), x.clone(), x];

while

let v: Vec<_> = iter::repeat_with(|| f()).take(3).collect();

behaves essentially like

let v = vec![f(), f(), f()];
1 Like

thanks :+1:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.