113
dereferencing it may result in a segmentation fault. Or it might point to a valid memory
range, but not the one that the user expects it to point to, resulting in unexpected and
undetermined behavior.
To solve this problem in persistent memory programming, a different type of pointer
is needed. libpmemobj introduced a C struct called PMEMoid, which consists of an
identifier of the pool and an offset from its beginning. This fat pointer is encapsulated
in libpmemobj C++ bindings as a template class pmem::obj::persistent_ptr. Both
the C and C++ implementations have the same 16-byte footprint. A constructor
from raw PMEMoid is provided so that mixing the C API with C++ is possible. The
pmem::obj::persistent_ptr is similar in concept and implementation to the smart
pointers introduced in C++11 (std::shared_ptr, std::auto_ptr, std::unique_ptr, and
std::weak_ptr), with one big difference – it does not manage the object’s life cycle.
Besides operator*, operator->, operator[], and typedefs for compatibility with
std::pointer_traits and std::iterator_traits, the pmem::obj::persistent_ptr
also has defined methods for persisting its contents. The pmem::obj::persistent_ptr
can be used in standard library algorithms and containers.
Transactions
Being able to modify more than 8 bytes of storage at a time atomically is imperative for
most nontrivial algorithms one might want to use in persistent memory. Commonly, a
single logical operation requires multiple stores. For example, an insert into a simple listbased queue requires two separate stores: a tail pointer and the next pointer of the last
element. To enable developers to modify larger amounts of data atomically, with respect
to power-fail interruptions, the PMDK library provides transaction support in some of
its libraries. The C++ language bindings wrap these transactions into two concepts: one,
based on the resource acquisition is initialization (RAII) idiom and the other based on
a callable std::function object. Additionally, because of some C++ standard issues,
the scoped transactions come in two flavors: manual and automatic. In this chapter we
only describe the approach with std::function object. For information about RAIIbased transactions, refer to libpmemobj-cpp documentation (https://pmem.io/pmdk/
cpp_obj/).
The method which uses std::function is declared as
void pmem::obj::transaction::run(pool_base &pop,
std::function tx, Locks&... locks)
Chapter 8 libpmemobj-Cpp: the adaptable language - C++ and persistent memory
Précédent

- 139/457

Suivant