rust
singleton
DesignPatterns

RustでSingletonパターン

はじめに

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

おわり