C++ bindings for libpmemobj (part 7) - synchronization primitives

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.

Mutex

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:

pmem::obj::mutex pmutex;
{
    std::lock_guard<pmem::obj::mutex> lock(pmutex);
}
std::unique_lock<pmem::obj::mutex> lock(pmutex);

Shared Mutex and Timed Mutex

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:

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.

Condition Variable

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:

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.

[This entry was edited on 2017-12-11 to reflect the name change from NVML to PMDK.]
Share this Post:

Related Posts: