UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
TransactionallySafeRecursiveMutex.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "AutoRTFM.h"
7
8#if UE_AUTORTFM
11#endif
12
13namespace UE
14{
15
16#if UE_AUTORTFM
17
18// A transactionally safe recursive mutex that works in the following novel ways:
19// - In the open (non-transactional):
20// - Take the lock like before. Simple!
21// - Free the lock like before too.
22// - In the closed (transactional):
23// - During locking we query `TransactionalLockCount`:
24// - 0 means we haven't taken the lock within our transaction nest and need to acquire the lock.
25// - Otherwise we already have the lock (and are preventing non-transactional code seeing any
26// modifications we've made while holding the lock), so just bump `TransactionalLockCount`.
27// - We also register an on-abort handler to release the lock should we abort (but we need to
28// query `TransactionalLockCount` even there because we could be aborting an inner transaction
29// and the parent transaction still wants to have the lock held!).
30// - During unlocking we defer doing the unlock until the transaction commits.
31//
32// Thus with this approach we will hold this lock for the *entirety* of the transactional nest should
33// we take the lock during the transaction, thus preventing non-transactional code from seeing any
34// modifications we should make.
36{
38 {
39 }
40
41 void Lock()
42 {
43 if (AutoRTFM::IsTransactional() || AutoRTFM::IsCommittingOrAborting())
44 {
46 {
47 // The transactional system which can increment TransactionalLockCount
48 // is always single-threaded, thus this is safe to check without atomicity.
49 if (0 == State->TransactionalLockCount)
50 {
51 State->Mutex.Lock();
52 }
53
54 State->TransactionalLockCount += 1;
55 };
56
57 // We explicitly copy the state here for the case that `this` was stack
58 // allocated and has already died before the on-abort is hit.
59 AutoRTFM::OnAbort([State = AutoRTFM::TOpenWrapper{this->State}]
60 {
61 ensure(0 != State.Object->TransactionalLockCount);
62
63 State.Object->TransactionalLockCount -= 1;
64
65 if (0 == State.Object->TransactionalLockCount)
66 {
67 State.Object->Mutex.Unlock();
68 }
69 });
70 }
71 else
72 {
73 State->Mutex.Lock();
74 ensure(0 == State->TransactionalLockCount);
75 }
76 }
77
78 void Unlock()
79 {
80 if (AutoRTFM::IsTransactional() || AutoRTFM::IsCommittingOrAborting())
81 {
82 // We explicitly copy the state here for the case that `this` was stack
83 // allocated and has already died before the on-commit is hit.
84 AutoRTFM::OnCommit([State = AutoRTFM::TOpenWrapper{this->State}]
85 {
86 ensure(0 != State.Object->TransactionalLockCount);
87
88 State.Object->TransactionalLockCount -= 1;
89
90 if (0 == State.Object->TransactionalLockCount)
91 {
92 State.Object->Mutex.Unlock();
93 }
94 });
95 }
96 else
97 {
98 ensure(0 == State->TransactionalLockCount);
99 State->Mutex.Unlock();
100 }
101 }
102
103 [[nodiscard]] bool TryLock()
104 {
105 if (AutoRTFM::IsTransactional() || AutoRTFM::IsCommittingOrAborting())
106 {
107 // TODO: implement transactional TryLock. #jira SOL-8303
108 return false;
109 }
110 else
111 {
112 ensure(0 == State->TransactionalLockCount);
113 return State->Mutex.TryLock();
114 }
115 }
116
117private:
119
120 struct FState final
121 {
124
125 FState() = default;
126
127 ~FState()
128 {
130 }
131 };
132
134};
135
136using FTransactionallySafeRecursiveMutex = ::UE::FTransactionallySafeRecursiveMutexDefinition;
137
138#else
140#endif
141
142} // namespace UE
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define UE_NONCOPYABLE(TypeName)
Definition CoreMiscDefines.h:457
TSharedRef< InObjectType, InMode > MakeShared(InArgTypes &&... Args)
Definition SharedPointer.h:2009
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
FRWLock Lock
Definition UnversionedPropertySerialization.cpp:921
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition OpenWrapper.h:28
Definition SharedPointer.h:692
Definition RecursiveMutex.h:19
UE::FRecursiveMutex Mutex
Definition MeshPaintVirtualTexture.cpp:164
State
Definition PacketHandler.h:88
Definition AdvancedWidgetsModule.cpp:13
::UE::FRecursiveMutex FTransactionallySafeRecursiveMutex
Definition TransactionallySafeRecursiveMutex.h:139