flo
October 3, 2024, 7:47pm
1
Hello,
I'd like to use a global variable in a multi-threading application.
I naively wrote this code :
use std::sync::{Arc, Mutex};
struct UserSession {
hash: u128,
user: String,
}
struct Global {
session_list: Arc<Mutex<Vec<UserSession>>>,
}
impl Global {
fn new() -> Self {
Self {
session_list: Arc::new(Mutex::new(Vec::new())),
}
}
}
static mut GLOBAL: Global = Global::new();
fn main() {
/* ...CODE... */
}
This doesn't compile, recommending to use LazyBlock :
error[E0015]: cannot call non-const fn `Global::new` in statics
--> src/main.rs:18:29
|
18 | static mut GLOBAL: Global = Global::new();
| ^^^^^^^^^^^^^
|
= note: calls in statics are limited to constant functions, tuple structs and tuple variants
= note: consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`
But why this need of LazyLock ? Isn't there a way to initialize static variables at startup ?
You can just make your new
function const
.
const fn new() -> Self {
Aside from that, this shouldn't be static mut
, just static
, and you don't need Arc
(you need to remove Arc
to make new
const
anyway).
3 Likes
flo
October 3, 2024, 8:32pm
3
I do this:
use std::sync::{LazyLock, Mutex};
struct UserSession {
hash: u128,
user: String,
}
struct Global {
session_list: Mutex<Vec<UserSession>>,
}
impl Global {
const fn new() -> Self {
Self {
session_list: Mutex::new(Vec::new()),
}
}
}
static GLOBAL: LazyLock<Global> = Global::new();
fn main() {
/* ...CODE... */
}
but it throws this compilation error :
18 | static GLOBAL: LazyLock<Global> = Global::new();
| ^^^^^^^^^^^^^ expected `LazyLock<Global>`, found `Global`
|
= note: expected struct `LazyLock<Global>`
found struct `Global`
Have I missed something ?
LazyLock
is a way to effectively safely initialize static variables at startup (first use), with synchronization.
There is no guaranteed single-threaded pre-main-esque mechanism built into to the language (which would allow safe static initialization without synchronization).
But you don't need any of that since you can initialize at compile time (const fn new
).
static GLOBAL: Global = Global::new();
3 Likes
flo
October 3, 2024, 8:42pm
6
Haaa sorry ! Thanks it compiles well ! And @quinedot for the explainations !
1 Like
farnz
October 4, 2024, 9:46am
7
If you ever need LazyLock
in future, note that your initialization should be:
static GLOBAL: LazyLock<Global> = LazyLock::new(|| Global::new());
The closure is the code that's run the first time someone accesses GLOBAL
, or if someone explicitly calls GLOBAL.force()
to make sure it's been initialized (which you can do from - for example - main
if you need to make sure it's not going to run the initialization closure at an inconvenient time).
1 Like
system
Closed
January 2, 2025, 9:46am
8
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.