285
• Line 41: We are only storing the mtx object inside root object on
persistent memory.
• Lines 47-48: We open the persistent memory pool with the layout
name of “MUTEX”.
• Line 50: We obtain a pointer to the root data structure within the
pool.
• Line 52: We acquire the mutex.
• Lines 54-56: Close the pool and exit the program.
As you can see, we do not explicitly unlock the mutex within the main() function.
If we run this example several times, the main() function can always lock the mutex on
line 52. This works because the pmem::obj::v class template implicitly calls a default
constructor, which is a wrapped std::mutex object type. The constructor is called every
time we open the persistent memory pool so we never run into a situation where the lock
is already acquired.
If we change the mtx object type on line 41 from pobj::experimental::v
tex> to std::mutex and try to run the program again, the example will hang during the
second run on line 52 because mtx object was locked during the first run and we never
released it.
Atomic Operations and Persistent Memory
Atomic operations cannot be used inside PMDK transactions for the reason described
in Figure 14-1. Changes made by atomic operations inside a transaction become
visible to other concurrent threads before the transaction is committed. It forces data
inconsistency issues in cases of abnormal program termination or transaction aborts.
Consider lock-free algorithms where concurrency is achieved by atomically updating the
state in memory.
Lock-Free Algorithms and Persistent Memory
It is intuitive to think that lock-free algorithms are naturally fit for persistent memory. In
lock-free algorithms, thread-safety is achieved by atomic transitions between consistent
states, and this is exactly what we need to support data consistency in persistent
memory. But this assumption is not always correct.
Chapter 14 ConCurrenCy and persistent MeMory
• Line 41: We are only storing the mtx object inside root object on
persistent memory.
• Lines 47-48: We open the persistent memory pool with the layout
name of “MUTEX”.
• Line 50: We obtain a pointer to the root data structure within the
pool.
• Line 52: We acquire the mutex.
• Lines 54-56: Close the pool and exit the program.
As you can see, we do not explicitly unlock the mutex within the main() function.
If we run this example several times, the main() function can always lock the mutex on
line 52. This works because the pmem::obj::v
constructor, which is a wrapped std::mutex object type. The constructor is called every
time we open the persistent memory pool so we never run into a situation where the lock
is already acquired.
If we change the mtx object type on line 41 from pobj::experimental::v
second run on line 52 because mtx object was locked during the first run and we never
released it.
Atomic Operations and Persistent Memory
Atomic operations cannot be used inside PMDK transactions for the reason described
in Figure 14-1. Changes made by atomic operations inside a transaction become
visible to other concurrent threads before the transaction is committed. It forces data
inconsistency issues in cases of abnormal program termination or transaction aborts.
Consider lock-free algorithms where concurrency is achieved by atomically updating the
state in memory.
Lock-Free Algorithms and Persistent Memory
It is intuitive to think that lock-free algorithms are naturally fit for persistent memory. In
lock-free algorithms, thread-safety is achieved by atomic transitions between consistent
states, and this is exactly what we need to support data consistency in persistent
memory. But this assumption is not always correct.
Chapter 14 ConCurrenCy and persistent MeMory
