はじめに
ここ(stack overflow | How do I create a global, mutable singleton?)から引用してます。
引用元では生ポインタ使ってますが、Rustっぽくないので、Optionで代用してます。
標準ライブラリのみでやる
標準ライブラリ以外の方法は上記参照
use std::sync::{Arc, Mutex, Once, ONCE_INIT};
use std::time::Duration;
use std::{mem, thread};
#[derive(Clone)]
struct SingletonReader {
// 同時アクセスのための参照及びミューテックス
inner: Arc<Mutex<u8>>,
}
fn singleton() -> Box<SingletonReader> {
// 生ポインタ遣うのあんまり好きじゃないので、Optionで代用。
static mut SINGLETON: Option<Box<SingletonReader>>=None;
static ONCE: Once = ONCE_INIT;
unsafe {
ONCE.call_once(|| {
// Singletonを作成する。ここは1回しか通らないらしい。なおStable
let singleton = SingletonReader {
inner: Arc::new(Mutex::new(0)),
};
// ヒープ領域に置いとく
SINGLETON = Some(Box::new(singleton));
});
// ヒープにあるオブジェクトの参照をコピーして使う
SINGLETON.clone().unwrap()
}
}
fn main() {
// スレッドで使う。
let threads: Vec<_> = (0..=10)
.map(|i| {
thread::spawn(move || {
thread::sleep(Duration::from_millis(i * 10));
let s = singleton();
let mut data = s.inner.lock().unwrap();
*data += i as u8;
})
})
.collect();
// 値の変化を確認
for _ in 0u8..20 {
thread::sleep(Duration::from_millis(5));
let s = singleton();
let data = s.inner.lock().unwrap();
println!("It is: {}", *data);
}
// 全体のスレッドが終わるまで待つ(多分大体終わってるはずだけど、念のためみたい)
for thread in threads.into_iter() {
thread.join().unwrap();
}
}
おわり