Posted at

RustでSingletonパターン

More than 1 year has passed since last update.


はじめに

ここ(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();
}
}

おわり