Hi,
I have this issue while factorising a piece of code to make a function more readable but I can't get my head around this error:
I'm believing it should be doable but malaxing the code doesn't led me anywhere yet
Hi,
I have this issue while factorising a piece of code to make a function more readable but I can't get my head around this error:
I'm believing it should be doable but malaxing the code doesn't led me anywhere yet
It is not possible to directly return a reference to something behind a mutex. If this were allowed, and there were no MutexGuard
in the picture, then the mutex wouldn't be able to track how long it's used for and when it can be unlocked. So, no, this shouldn't be doable. You should instead return the mutex guard.
Also, if you are (correctly) using Lazy
for storing globals, you shouldn't need any unsafe
at all for this.
Don't mind me, I think that a Mutex::get_mut()
instead of Mutex::lock()
would do the trick
Even with get_mut()
instead of lock()
?
Without unsafe
, rustc is unhappy, what am I missing?
EDIT: rust-analyzer is unhappy, rustc is
Even more so, when you have a global. Shared mutability is forbidden, and if you don't actually perform the synchronization, then you can trivially invoke get_value()
twice with the same key, causing aliasing &mut
s (already instant UB!) as well as a race condition. static mut
is an anti-pattern and it should never be used, basically.
Even if it's protected with a Mutex?
If you get_mut()
, and not lock()
, then it's not protected.
The get_mut()
method is for when you can prove at compile time that you're the only one who is accessing the mutex. In that case, there's no reason to lock the mutex. You can't use it otherwise.
The documentation of get_mut
says:
the mutable borrow statically guarantees no locks exist.
So it's explicitly saying it's not locking, which is wrong when you have a mutable global.
Ok, I was understanding "no lock needed", I guess I need to get rid of this global then
But rustc will not check that for me, will it?
Of course it will! Aliased mutability and race conditions are the exact reasons why accessing a mutable global is unsafe
.
also, you cant just use unsafe
at random places to make the compiler happy. unsafe is reserved for when you can guarantee that the operations inside it cannot cause safety issues
Rustc will check that you're the only one who can access the mutex when using get_mut
unless you use unsafe to incorrectly create a mutable reference to the mutex.
thanks @alice and @H2CO3, using get_mut()
with no unsafe (I need to raise an issue for rust-analyzer) and rustc is happy!
There were multiple, other problems with your code, e.g. the incorrect (too short) scope of the ctxs
variable, or the "check if key exists otherwise insert" anti-pattern which doesn't work and should be expressed using the Entry
API.
static SRV_CTXS: Lazy<Mutex<HashMap<String, MyType>>> = Lazy::new(Mutex::default);
async fn get_value(key: &str) -> MappedMutexGuard<'static, MyType> {
MutexGuard::map(
SRV_CTXS.lock().await,
|map| map.entry(key.to_owned()).or_insert_with(MyType::default)
)
}
Something must be still wrong there; it's not possible to access a global mutably without unsafe
.
yes, there was another error that was masking the rest need more work
Just use the code I posted above.