nlib
misc/threading/safeinit/safeinit.cpp

This sample shows how to safely and efficiently run initialization in multiple threads.

It uses nlib_once to write the dependencies between the initialization processes, and runs once when each initialization process is needed.

The procedure is as follows.

  1. Define tag types for each initialization process. In this sample, these tag types are a_init_tag through d_init_tag.
  2. Use the tags to code the definitions for flag_ and error_ for each instantiation of the SafeInit class template.
  3. Use the tags to implement the OnceFunc function for each instantiation of the SafeInit class template.
  4. The initialization process can be executed with SafeInit<tag type>::Init().

The dependencies for the initialization sequence are described in the OnceFunc function called through nlib_once. By using nlib_once, the initialization function calls do not collide, even if initialization processes are run on multiple threads.

In the sample, the dependencies are written as 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(&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