nlib
nn::nlib::HandleMaker< HBODY > クラステンプレート

32bit整数値を持つハンドルの実装を支援するクラスです。 [詳解]

#include "nn/nlib/HandleMaker.h"

公開メンバ関数

 HandleMaker (HandleTable< HBODY > *ptr) noexcept
 コンストラクタです。テーブルへのポインタを渡す必要があります。
 
errno_t AttachHandleBody (int *handle, HBODY *body) noexcept
 ハンドルの実体に関連付けられるハンドルを取得します。 [詳解]
 
errno_t GetHandleAccess (int handle, HandleAccess< HBODY > *access) noexcept
 ハンドルからハンドルの実体へのアクセスを得ます。 [詳解]
 

詳解

template<class HBODY>
class nn::nlib::HandleMaker< HBODY >

32bit整数値を持つハンドルの実装を支援するクラスです。

テンプレート引数
HBODYハンドルの実体の型
説明
32bit整数値(以降ハンドル)とオブジェクト(以降ハンドルの実体)との関連付けを行う仕組みを提供するクラスです。 HandleMakerを利用すると以下のような特徴を持つハンドルを簡単に提供することが可能になります。
  • ハンドルを通したハンドルの実体へのアクセスはスレッドセーフになります。
  • ハンドルをクローズした後にそのハンドル(つまり無効なハンドル)を利用した場合でも、クラッシュせずにエラー(一般にはEBADF)を返すことができます。
  • 上記は異なるスレッドからクローズされた場合も同様です。
  • ハンドルとなる整数値はすぐには再利用されないので、意図しないハンドルの実体へのアクセスを避けることができます。
  • -1, 0, 1, 2, 3はハンドルの値として割り当てられることはありません。
以下が簡単なハンドルを定義するコード例になります。
class MyHandleBody {
public:
// 以下はHandleMakerから利用される
static const size_t N = 128; // 同時に存在するMyHandleBodyオブジェクトの最大数
void Lock() { nlib_mutex_lock(&lock_); } // リソースのロック
void Unlock() { nlib_mutex_unlock(&lock_); } // リソースのアンロック
bool IsHandleBodyEnabled() { return valid_; } // 利用可能かどうか
public:
MyHandleBody() {
valid_ = false;
nlib_mutex_init(&lock_);
}
~MyHandleBody() noexcept {
// デストラクタ内で例外を投げてはならない
assert(!valid_);
}
errno_t Initialize(......) {
assert(!valid_);
{
// オープン等の初期化処理
}
valid_ = true;
return 0;
}
errno_t Finalize() {
// lock_はロックされている
if (!valid_) {
// lock_を待っている間にFinalize()が実行されている可能性がある。
// また、Finalize()後もlock_のロックは可能である必要がある。
return EBADF;
}
{
// クローズ等の終了処理
}
valid_ = false;
return 0; // もしエラーを返してもハンドルは解放される。
}
errno_t access_method(......) {
// lock_はロックされている
if (!valid_) {
// lock_を待っている間にFinalize()が実行されている可能性がある。
return EBADF;
}
{
// ハンドル実体の利用
}
return 0;
}
private:
bool valid_;
nlib_mutex lock_;
// other data members ...
};
static nlib_ns::HandleTable<MyHandleBody> table_ = NLIB_HANDLETABLE_INITIALIZER;
// myhandle_open(), myhandle_close(), myhandle_access()はスレッドセーフ
errno_t myhandle_open(int* handle) {
MyHandleBody* p = new(std::nothrow) MyHandleBody();
if (!p) return ENOMEM;
e = p->Initialize()
if (nlib_is_error(e)) {
delete p;
return e;
}
// ハンドルの実体に対してハンドルの割り当てを行う
e = maker.AttachHandleBody(handle, p);
if (nlib_is_error(e)) {
// 割り当てられるハンドルがなかった。
(void)p->Finalize();
delete p;
return e; // ENFILE
}
return 0;
}
errno_t myhandle_access(int handle, ......) {
e = maker.GetHandleAccess(handle, &access);
if (nlib_is_error(e)) return e; // EBADF
e = access->access_method(......);
return e;
}
errno_t myhandle_close(int handle) {
e = maker.GetHandleAccess(handle, &access);
if (nlib_is_error(e)) return e; // EBADF
access.DetachHandleBody();
e = access->Finalize();
return e;
}

HandleMaker.h87 行目に定義があります。

関数詳解

◆ AttachHandleBody()

template<class HBODY >
nn::nlib::HandleMaker< HBODY >::AttachHandleBody ( int *  handle,
HBODY *  body 
)
noexcept

ハンドルの実体に関連付けられるハンドルを取得します。

引数
[out]handlebodyに関連付けられるハンドルへのポインタ
[in]bodyハンドルに関連付けるハンドルの実体
戻り値
0成功しました。
ENFILE割り当てることのできるハンドルがありません。

HandleMaker.h192 行目に定義があります。

◆ GetHandleAccess()

template<class HBODY >
nn::nlib::HandleMaker< HBODY >::GetHandleAccess ( int  handle,
HandleAccess< HBODY > *  access 
)
noexcept

ハンドルからハンドルの実体へのアクセスを得ます。

引数
[in]handleAttachHandleBody()で取得したハンドル
[out]accesshandleに対応する実体へのアクセサ
戻り値
0成功しました。
EBADFハンドルが有効ではありません。

HandleMaker.h259 行目に定義があります。


このクラス詳解は次のファイルから抽出されました: