Класс Once
Класс Once из модуля std::sync
предназначен для однократного выполнения
некоторого кода. Он гарантирует, что
переданная функция будет вызвана ровно
один раз, даже если несколько потоков
попытаются сделать это одновременно.
Класс полезен для ленивой инициализации
глобальных данных, настройки разделяемых
ресурсов и выполнения других операций,
которые должны произойти только один раз
за всё время работы программы.
Основной метод call_once принимает
замыкание, которое нужно выполнить
однократно. Если несколько потоков
вызовут call_once одновременно,
только один из них выполнит замыкание,
а остальные будут ожидать завершения.
Синтаксис
use std::sync::Once;
let once = Once::new();
once.call_once(|| {
// код, который выполнится один раз
});
Пример
Давайте создадим Once и вызовем
call_once несколько раз, чтобы
убедиться, что замыкание выполняется
только один раз:
use std::sync::Once;
fn main()
{
let once = Once::new();
let mut counter = 0;
once.call_once(|| {
counter += 1;
println!("Инициализация выполнена");
});
once.call_once(|| {
counter += 1;
println!("Этот код не выполнится");
});
println!("counter = {}", counter);
}
Результат выполнения кода:
"Инициализация выполнена"
"counter = 1"
Пример
Давайте используем Once для ленивой
инициализации глобальной конфигурации,
доступной из нескольких потоков:
use std::sync::{Once, Mutex};
use std::thread;
static INIT: Once = Once::new();
static mut CONFIG: Option<String> = None;
fn get_config() -> &'static str
{
INIT.call_once(|| {
unsafe {
CONFIG = Some(String::from("abcde"));
}
});
unsafe {
CONFIG.as_ref().unwrap()
}
}
fn main()
{
let handles: Vec<_> = (0..3).map(|_| {
thread::spawn(|| {
println!("{}", get_config());
})
}).collect();
for handle in handles {
handle.join().unwrap();
}
}
Результат выполнения кода:
"abcde"
"abcde"
"abcde"