nlib
misc/threading/safeinit/safeinit.cpp

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

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

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

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

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

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

/*---------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)2012-2016 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
*---------------------------------------------------------------------------*/
#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(&flag_, OnceFunc);
return error_;
}
private:
static nlib_onceflag flag_;
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<> nlib_onceflag SafeInit<a_init_tag>::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>::error_ = false;
template<> nlib_onceflag SafeInit<b_init_tag>::flag_ = NLIB_ONCE_INIT;
template<> void SafeInit<b_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init(); // 'b' depends 'a'.
if (err) {
error_ = true;
return;
}
nlib_printf("SafeInit<b_init_tag>::OnceFunc()\n");
}
template<> bool SafeInit<c_init_tag>::error_ = false;
template<> nlib_onceflag SafeInit<c_init_tag>::flag_ = NLIB_ONCE_INIT;
template<> void SafeInit<c_init_tag>::OnceFunc() {
bool err;
err = SafeInit<a_init_tag>::Init(); // 'c' depends 'a'.
if (err) {
error_ = true;
return;
}
nlib_printf("SafeInit<c_init_tag>::OnceFunc()\n");
}
template<> bool SafeInit<d_init_tag>::error_ = false;
template<> nlib_onceflag SafeInit<d_init_tag>::flag_ = NLIB_ONCE_INIT;
template<> void SafeInit<d_init_tag>::OnceFunc() {
bool err;
err = SafeInit<b_init_tag>::Init(); // 'd' depends 'b'.
if (err) {
error_ = true;
return;
}
err = SafeInit<c_init_tag>::Init(); // 'd' depends 'c'.
if (err) {
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