nlib
misc/threading/safeinit/safeinit.cpp

複数スレッドで行われる初期化処理を安全かつ効率よく行うためのサンプルです。

nlib_once()を利用して初期化処理間の依存関係を記述し、それぞれの初期化処理を必要なときに1回だけ実行するという処理を行っています。

使い方は以下のとおりです。

  1. 初期化処理毎にタグ型を定義する。サンプル内ではa_init_tagからd_init_tagです。
  2. 各タグで実体化したSafeInitクラステンプレートごとにm_Flag, m_Errorの定義を記述する。
  3. 各タグで実体化したSafeInitクラステンプレートごとにOnceFunc()関数を実装する。
  4. SafeInit<タグ型>:: Init()によって初期化処理を実行することができる。

初期化順の依存関係は、nlib_once()経由で実行されるOnceFunc()内に記述します。 nlib_once()を利用するため、複数のスレッドで初期化処理を実行しても初期化関数が重複して呼び出されることはありません。

サンプル内では、a->b, a->c, b->d, c->dの依存関係が記述されています。

#include "nn/nlib/Config.h"
template<class TAG, class ERRORTYPE = bool>
class SafeInit {
public:
typedef ERRORTYPE ErrorType;
typedef TAG TagType;
static const ErrorType& Init() {
// You can implement timeout by using nlib_tryonce().
nlib_once(&m_Flag, OnceFunc);
return m_Error;
}
private:
static nlib_onceflag m_Flag;
static ErrorType m_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>::m_Error = false;
template<> nlib_onceflag SafeInit<a_init_tag>::m_Flag = NLIB_ONCE_INIT;
template<> void SafeInit<a_init_tag>::OnceFunc() {
nlib_printf("SafeInit<a_init_tag>::OnceFunc()\n");
}
template<> bool SafeInit<b_init_tag>::m_Error = false;
template<> nlib_onceflag SafeInit<b_init_tag>::m_Flag = NLIB_ONCE_INIT;
template<> void SafeInit<b_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init(); // 'b' depends 'a'.
if (err) {
m_Error = true;
return;
}
nlib_printf("SafeInit<b_init_tag>::OnceFunc()\n");
}
template<> bool SafeInit<c_init_tag>::m_Error = false;
template<> nlib_onceflag SafeInit<c_init_tag>::m_Flag = NLIB_ONCE_INIT;
template<> void SafeInit<c_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init(); // 'c' depends 'a'.
if (err) {
m_Error = true;
return;
}
nlib_printf("SafeInit<c_init_tag>::OnceFunc()\n");
}
template<> bool SafeInit<d_init_tag>::m_Error = false;
template<> nlib_onceflag SafeInit<d_init_tag>::m_Flag = NLIB_ONCE_INIT;
template<> void SafeInit<d_init_tag>::OnceFunc() {
bool err;
err = SafeInit<b_init_tag>::Init(); // 'd' depends 'b'.
if (err) {
m_Error = true;
return;
}
err = SafeInit<c_init_tag>::Init(); // 'd' depends 'c'.
if (err) {
m_Error = true;
return;
}
nlib_printf("SafeInit<d_init_tag>::OnceFunc()\n");
}
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