Replacing lazy_statics with const_mutexes (parking_lot)

instead of the ugly lazy_static { pub static ref .. } blocks, having a single line as such looks way better:

const MY_T: Mutex<Option<T>> = parking_lot::const_mutex(None);

fn access_later(t: T) {
    MY_T.lock().replace(t);
}

This compiles, and there is no exposed unsafe code. What do you guys think about this approach? Is this even valid?

A const will copy a new instance of that constant value wherever that name is used, which isn't very helpful for synchronization. You probably want a static instead.

3 Likes

Yeah, I thought it was too good to be true ..

I just need to take pass a Vec<u8> from a FFI boundary to an asynchronous event loop. I want to use an UnboundedSender<Vec<u8>> to achieve this. Since the channel is Send + Sync, wouldn't it be fine to use a static mut sender: Option<UnboundedSender<Vec<u8>> = None?

This one (which uses static) compiles and passes the asserts:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d0baee8880645b6724f09dd293a70f6b

use parking_lot::Mutex; // 0.11.0

#[derive(Debug, PartialEq)]
pub struct Foo(u32);

pub static MY_T: Mutex<Option<Foo>> = parking_lot::const_mutex(None);

pub fn access_later(t: Foo) -> Option<Foo> {
    MY_T.lock().replace(t)
}

fn main() {
    assert_eq!(access_later(Foo(5)), None);
    assert_eq!(access_later(Foo(8)), Some(Foo(5)));
    assert_eq!(access_later(Foo(13)), Some(Foo(8)));
}
1 Like

Ìf you replace static with const it always returns None because it's a new Mutex<Foo> each time the MY_T is reached

   Compiling playground v0.0.1 (/playground)
    Finished dev [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/playground`
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `None`,
 right: `Some(Foo(5))`', src/main.rs:14:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Option isn’t Sync though. If you set it to Some at the start of the program and pinky swear you won’t remove it then it would work. Alternatively it’s bit safer to initialize it with once_cell or lazy_static and get rid of the Option.

1 Like

static is a global variable so it has single address on runtime. const purely is a compile time only thing and it works like copy-pasting its initialization expression whenever used.

Putting a const mutex in a static (not const) is certainly not a bad idea!

1 Like

In addition, const items don't have any guarantee whatsoever of being threadsafe, it fully depends on what the value is within the const. lazy_static on the other hand does provide that guarantee.