複数スレッドで行われる初期化処理を安全かつ効率よく行うためのサンプルです。
nlib_once()
を利用して初期化処理間の依存関係を記述し、それぞれの初期化処理を必要なときに1回だけ実行するという処理を行っています。
使い方は以下のとおりです。
-
初期化処理毎にタグ型を定義する。サンプル内では
a_init_tag
からd_init_tag
です。
-
各タグで実体化した
SafeInit
クラステンプレートごとにflag_
, error_
の定義を記述する。
-
各タグで実体化した
SafeInit
クラステンプレートごとにOnceFunc()
関数を実装する。
-
SafeInit<タグ型>::Init()によって初期化処理を実行することができる。
初期化順の依存関係は、nlib_once()
経由で実行されるOnceFunc()
内に記述します。 nlib_once()
を利用するため、複数のスレッドで初期化処理を実行しても初期化関数が重複して呼び出されることはありません。
サンプル内では、a->b, a->c, b->d, c->d
の依存関係が記述されています。
template<class TAG, class ERRORTYPE = bool>
class SafeInit {
public:
typedef ERRORTYPE ErrorType;
typedef TAG TagType;
static const ErrorType& Init() {
return error_;
}
private:
static ErrorType error_;
static void OnceFunc();
};
struct a_init_tag {};
struct b_init_tag {};
struct c_init_tag {};
struct d_init_tag {};
template<> bool SafeInit<a_init_tag>::error_ = false;
template<> void SafeInit<a_init_tag>::OnceFunc() {
}
template<> bool SafeInit<b_init_tag>::error_ = false;
template<> void SafeInit<b_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init();
if (err) {
error_ = true;
return;
}
}
template<> bool SafeInit<c_init_tag>::error_ = false;
template<> void SafeInit<c_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init();
if (err) {
error_ = true;
return;
}
}
template<> bool SafeInit<d_init_tag>::error_ = false;
template<> void SafeInit<d_init_tag>::OnceFunc() {
bool err;
err = SafeInit<b_init_tag>::Init();
if (err) {
error_ = true;
return;
}
err = SafeInit<c_init_tag>::Init();
if (err) {
error_ = true;
return;
}
}
bool SafeInitDemo() {
bool err;
err = SafeInit<c_init_tag>::Init();
if (err) return false;
err = SafeInit<d_init_tag>::Init();
return !err;
}
static bool SampleMain(int, char**) { return SafeInitDemo(); }
NLIB_MAINFUNC