let a = Mutex::new(1);
println!("{:?}", a) // this prints that Mutex has a value 1
let a = Mutex::new(1);
a.lock(); //a.lock().await if using e.g. Tokio
println!("{:?}", a) // This also lets us know that Mutex has a value of 1 inside
I'm trying to peek value wrapped inside the mutex while not acquiring a lock. I have no intent to mutate the value, just "seeing". I learned that RwLock might allow us to do it but also have discovered that "debug formatter" does seem to access the value inside Mutex. It does so even when the lock has been taken.
Could someone explain why/how this can happen? Would there be a way to see the value inside the mutex without getting the lock?
EDIT
I missed one important thing. I've been actually dealing with Arc, as in
let a = Arc::new(Mutex::new(1));
let c = a.clone()
println!("{:?}", c);
warning: unused `Result` that must be used
--> src/main.rs:5:5
|
5 | a.lock();
| ^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: this `Result` may be an `Err` variant, which should be handled
If you fix that with a.lock().unwrap() then it tells you:
warning: unused `MutexGuard` that must be used
--> src/main.rs:5:5
|
5 | a.lock().unwrap();
| ^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: if unused the Mutex will immediately unlock
You need to save the lock guard to keep the mutex locked. Otherwise it's only a temporary value and is dropped when the statement ends.
use std::sync::Mutex;
fn main() {
let a = Mutex::new(1);
let _lock = a.lock().unwrap();
println!("{:?}", a);
}
This outputs:
Mutex { data: <locked>, poisoned: false, .. }
Now the mutex is locked and can't be read.
By the way, looking at the standard library's source is a great way to see what's going on under the covers. You can see in Mutex's source code that it does indeed try to lock itself when printing:
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("Mutex");
match self.try_lock() {
...
}
...
}
}
The whole point of the lock is specifically so that others can't see any mutations that might be happening concurrently. You have to lock the mutex to ensure nobody else is currently mutating it. There's no way to read the value without locking it, and the mutex would arguably not be doing its job if you could.
You can use RwLock if you want multiple concurrent readers, but they will all still all have to lock it to ensure there are no concurrent writers.