This example shows how to define an integer handle that you can use within a process, by using nn::nlib::HandleMaker
.
Referencing an object indirectly using an integer handle provides advantages as listed below:
-
A pointer to the object can be used without exposing that pointer.
-
Access to a closed object can be prevented.
-
An error can be reported without causing a crash even when doing multiple close operations simultaneously.
Using the nn::nlib::HandleMaker
class allows you to easily create a code that assigns an integer handle to an object.
#include <memory>
class MyHandleBody {
public:
static const size_t N = 128;
public:
valid_ = false;
access_count_ = 0;
}
NLIB_ASSERT(!valid_);
}
NLIB_ASSERT(!valid_);
valid_ = true;
return 0;
}
if (!valid_) {
return EBADF;
}
valid_ = false;
return 0;
}
if (!valid_) {
return EBADF;
}
++access_count_;
nlib_printf(
"myhandle_access() from thread %d : access_count = %d\n",
id, access_count_);
return 0;
}
private:
bool valid_;
int access_count_;
};
std::unique_ptr<MyHandleBody> p(new (std::nothrow) MyHandleBody());
if (!p) return ENOMEM;
e = p->Initialize();
if (e != 0) {
return e;
}
e = maker.AttachHandleBody(handle, p.get());
(void)p->Finalize();
return e;
}
p.release();
return 0;
}
e = maker.GetHandleAccess(handle, &access);
if (e != 0) return e;
e = access->access_method();
return e;
}
e = maker.GetHandleAccess(handle, &access);
if (e != 0) return e;
e = access->Finalize();
return e;
}
bool SampleHandleMaker() {
int h;
const size_t kNumThread = 8;
e = myhandle_open(&h);
if (e != 0) return false;
auto thread_func = [](void* ph) {
int handle = (int)(intptr_t)ph;
for (int j = 0; j < 3; ++j) {
err = myhandle_access(handle);
if (err == EBADF) {
nlib_printf(
"myhandle_access() from thread %d, but handle already closed\n",
id);
break;
}
}
err = myhandle_close(handle);
};
for (size_t i = 0; i < kNumThread; ++i) {
NLIB_ASSERT(e == 0);
}
for (size_t i = 0; i < kNumThread; ++i) {
}
return true;
}
bool SampleMain(int, char**) { return SampleHandleMaker(); }
NLIB_MAINFUNC