It is not possible, also what you wrote is most probably not what you meant to do.
The mutex guard has the goal to unlock the mutex when it's dropped. If you bind a lifetime of the guard to the mutex itself, you are saying that it will never be dropped, thus the mutex will always be locked.
Anyway, why do you need the reference to the guard itself? Usually you wouldn't care, you just expect it to keep the lock, as long as it's referenced.
Maybe you want to do this? One needs more context to see if this is exactly what you are trying to do :D
use std::sync::{Arc, Mutex, MutexGuard};
struct Test {
mutex: Arc<Mutex<()>>,
}
impl Test {
pub fn new() -> Self {
let mutex = Arc::new(Mutex::new(()));
Self { mutex }
}
pub fn try_download(&self) -> Option<MutexGuard<()>> {
let guard = self.mutex.try_lock();
if guard.is_ok() {
println!("Download started!");
return guard.ok();
} else {
println!("Cannot download since it's already downloading");
return None;
}
}
}
fn main() {
let test = Test::new();
// This could be kept alive like you said in an hashmap, so the guard is not dropped
// v
let a = test.try_download(); // Download started!
let b = test.try_download(); // Cannot download since it's already downloading
}
Why your code doesn't work
There are actually 2 problems
- Reference to an unknown stack space (segfault!)
impl<'a> Test<'a> {
pub fn new() -> Self {
let mutex = Arc::new(Mutex::new(()));
// ^
// This reference has the lifetime of mutex
// v
let guard = &mutex.lock().unwrap();
Self {
mutex, // mutex is moved here, so guard points to something which is at this time
// unknown. This can be known only after the new stack frame is built
guard,
}
}
}
- where is the mutex really stored? In your example it's on the stackframe of the function new. You then store a pointer to it in a struct and return it. By returning you also drop the stack, so where does the pointer points at? (segfault!)
impl<'a> Test<'a> {
pub fn new() -> Self {
let mutex = Arc::new(Mutex::new(()));
// MutexGuard is created here and put in the stack dropped when the function exits.
// v
let guard = &mutex.lock().unwrap();
Self { mutex, guard }
}
}
MutexGuard
in the struct shouldn't be a reference, it should be justMutexGuard<'a, ()>
, otherwise you're returning a reference to a local variable which just can't work. But even after making this change,guard
is pointing insidemutex
, so you're effectively creating a self-referential data structure, and that won't compile. The only way for that to work is using unsafe. – Astigmaticunsafe
in this situation? – Lukewarm