tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_LockFreeObject.h
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11#pragma once
12
13namespace tracktion { inline namespace graph
14{
15
16//==============================================================================
17//==============================================================================
36template<typename ObjectType>
38{
39public:
48
50 void clear()
51 {
52 // Obtain the locks for both the objects
53 std::scoped_lock sl (clearObjectsMutex);
54 std::scoped_lock sl2 (pushingObjectMutex);
55
56 pendingObjectStorage = {};
57 objectStorage = {};
58
59 pendingObject = nullptr;
60 }
61
63 void pushNonRealTime (ObjectType&& newObj)
64 {
65 // Obtain the lock on the pending object
66 std::scoped_lock sl (pushingObjectMutex);
67
68 pendingObjectStorage = std::move (newObj);
69 pendingObject = &pendingObjectStorage;
70 }
71
79 ObjectType* retainRealTime()
80 {
81 if (clearObjectsMutex.try_lock())
82 {
83 needToUnlockClearObjectsMutex = true;
84 }
85 else
86 {
87 needToUnlockClearObjectsMutex = false;
88 return nullptr;
89 }
90
91 // If we get the lock, we can update
92 if (pushingObjectMutex.try_lock())
93 {
94 needToUnlockPushingObjectMutex = true;
95
96 // Move any penidng object in to the main objectStorage
97 if (auto newObject = pendingObject.exchange (nullptr))
98 std::swap (objectStorage, *newObject);
99 }
100 else
101 {
102 needToUnlockPushingObjectMutex = false;
103 }
104
105 // Then return the main stored object
106 return &objectStorage;
107 }
108
111 {
112 if (needToUnlockClearObjectsMutex)
113 clearObjectsMutex.unlock();
114
115 if (needToUnlockPushingObjectMutex)
116 pushingObjectMutex.unlock();
117 }
118
119 //==============================================================================
124 {
125 public:
128 : lockFreeObject (lfo)
129 {}
130
133 {
134 lockFreeObject.releaseRealTime();
135 }
136
138 ObjectType* get() const
139 {
140 return object;
141 }
142
143 private:
144 LockFreeObject& lockFreeObject;
145 ObjectType* object { lockFreeObject.retainRealTime() };
146 };
147
150 {
151 return ScopedRealTimeAccess { *this };
152 }
153
154private:
155 ObjectType objectStorage, pendingObjectStorage;
156 std::atomic<ObjectType*> pendingObject { nullptr };
157 RealTimeSpinLock pushingObjectMutex, clearObjectsMutex;
158 bool needToUnlockPushingObjectMutex = false, needToUnlockClearObjectsMutex = true;
159};
160
161}} // namespace tracktion_engine
Helper class to automatically retain/release real time access to an object.
~ScopedRealTimeAccess()
Releases real time access to the object.
ScopedRealTimeAccess(LockFreeObject &lfo)
Retains real time access to an object.
ObjectType * get() const
Returns a pointer to the object if access was obtained.
Manages access to an object in a way that means it is lock-free to access from a real-time thread.
void clear()
Clears the object and any pending object by assigining them defaultly constructed objects.
LockFreeObject()
Constructs an initially empty object.
ScopedRealTimeAccess getScopedAccess()
Creates a ScopedRealTimeAccess for this LockFreeObject.
void pushNonRealTime(ObjectType &&newObj)
Pushes a new object to be picked up on the real time thread.
ObjectType * retainRealTime()
Retains the object for use in a real time thread.
void releaseRealTime()
Releases the use of the object from a previous call to retainRealTime.
A basic spin lock that uses an atomic_flag to store the locked state so should never result in a syst...
void unlock() noexcept
Releases the lock, this should only be called after a successful call to try_lock or lock.
bool try_lock() noexcept
Attempts to take the lock once, returning true if successful.
T exchange(T... args)
T is_pointer_v
T swap(T... args)