64
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

スレッドセーフな Singleton クラスを作成する

Last updated at Posted at 2013-10-02

有名な話であると思っていたが、つい最近嵌った同僚がいたのでメモすることにした。

注)下記内容は Visual C++ / C++11 未対応の g++ を使用している場合の話です

Singleton パターン

デザインパターンの一つ。あるクラスが一つのインスタンスしか持たないことを確実にしたい時に使用する。C++ での Singleton パターンの実装例は下記の通り。

// Singleton.h
#pragma once

class Singleton
{
    public:
        static Singleton &getInstance();
    private:
        Singleton(){}
        Singleton(const Singleton &other){}
        Singleton &operator=(const Singleton &other){}
};
// Singleton.cpp
#include "Singleton.h"

Singleton &Singleton::getInstance() {
    static Singleton instance;
    return instance;
}
// main.cpp
#include <iostream>
#include "Singleton.h"

int main()
{
    Singleton &singleton = Singleton::getInstance();
    // do something...
    return 0;
}

上記実装の問題点

Visual C++ / C++11 未対応の g++ を使用している場合、 上で示した実装にはスレッドセーフでないという問題がある。
例えば二つのスレッドが同時に Singleton::getInstance() を呼び出した場合、

  • Singleton インスタンスが二回作成される
  • 一方のスレッドで完全に初期化される前にもう片方のスレッドで Singleton インスタンスが使用される

のいずれかの問題が発生する可能性がある。

解決策 1 : 静的な初期化を行う

プログラムがまだシングルスレッドであると想定できる main() の前で Singleton クラスのインスタンスを作成すれば良い。静的な初期化を行うためには、下記コードを Singleton.cpp に追加すれば良い。

// Singleton.cpp
// 上で示した部分は省略
static Singleton &singleton = Singleton::getInstance();

解決策 2 : Singleton クラスの初期化ルーチンを追加する

例えば下記 init() の様な、Singleton クラス用に初期化ルーチンを追加する。
なお下記コードは C++11 のものであり、 C++11 以前の C++ を使用している場合、ミューテックスロックを行う処理は自作 (または他のライブラリを利用) する必要がある。

#include <mutex>

static std::mutex s_mutex;
void init() {
    std::lock_guard<std::mutex> lock(s_mutex);
    Singleton::getInstance();
}

解決策 3 : コンパイルオプション -fthreadsafe-statics を明示する

$ g++ -fthreadsafe-statics main.cpp Singleton.cpp

まとめ

スレッドセーフな Singleton クラスを作成するには

  • 静的な初期化
  • 初期化ルーチンの追加
  • コンパイルオプション -fthreadsafe-statics を明示する

などの方法が有効である。
なお、本問題を解決する方法を調べると DCLP (ダブルチェックロッキングパターン) という方法に出くわすと思う。
しかし DCLP は全てのコンパイラで確実に機能する保証は無いらしく、使用しない方が良いと思う。

64
62
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
64
62

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?