To finish off the C++ bindings to libpmemobj blog marathon, I will introduce to you the synchronization mechanisms we implemented. They are mostly C++11-like implementations of different kinds of mutexes and the condition variable. They satisfy their respective concepts (Mutex, SharedMutex and so on), the difference is that they are based on the persistent memory resident synchronization primitives provided by libpmemobj.
The pmem::obj::mutex
class satisfies the requirements of the Mutex and
StandardLayoutType concepts. The usage of this class should be really
straightforward for anyone who has ever used the std::mutex
. The only
difference is that the pmem::obj::mutex
has to be placed in persistent memory,
within a libpmemobj pool. This is because the implementation needs to be able to
reset the mutex the next time the pool is opened after a power failure/crash.
In persistent memory, the mutex would not be reinitialized automatically in
such case.
You can use the pmem::obj::mutex
with standard wrapper classes like:
1
2
3
4
5
pmem::obj::mutex pmutex;
{
std::lock_guard<pmem::obj::mutex> lock(pmutex);
}
std::unique_lock<pmem::obj::mutex> lock(pmutex);
The pmem::obj::shared_mutex
and pmem::obj::timed_mutex
are also very similar
to their std
counterparts. They also satisfy their respective SharedMutex
and TimedMutex as well as the StandardLayoutType concepts. Their usage is
also very straightforward:
1
2
3
4
5
6
7
8
9
pmem::obj::shared_mutex smutex;
pmem::obj::timed_mutex tmutex;
{
std::shared_lock<pmem::obj::shared_mutex> lock(smutex);
}
std::unique_lock<pmem::obj::shared_mutex> lock(smutex);
tmutex.try_lock_for(std::chrono::milliseconds(100));
std::unique_lock<pmem::obj::timed_mutex> lock(tmutex);
The pmem::obj::shared_mutex
and pmem::obj::timed_mutex
are persistent
memory resident synchronization mechanisms.
The pmem::obj::condition_variable
, as you probably by now noticed, is pretty
much the standard std::condition_variable
, with the exception of it being
persistent memory resident. The usage is also very similar:
1
2
3
4
5
6
pmem::obj::mutex pmutex;
pmem::obj::condition_variable cond;
pmutex.lock();
cond.wait(proot->pmutex, [&]() { /* check condition here */ });
// do some meaningful work here
pmutex.unlock();
With this we have ended the introduction to the core classes and functions of the C++ bindings to libpmemobj. If you ever find yourself in doubt about the usage of the C++ bindings or PMDK in general, don’t hesitate to send us a message on our Google Group.