UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MpscQueue.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
9#include "Misc/Optional.h"
10#include <atomic>
11
16template<typename T, typename AllocatorType = FMemory>
17class TMpscQueue final
18{
19public:
20 using ElementType = T;
21
23
25 {
26 FNode* Sentinel = ::new(AllocatorType::Malloc(sizeof(FNode), alignof(FNode))) FNode;
27 Head.store(Sentinel, std::memory_order_relaxed);
28 Tail = Sentinel;
29 }
30
32 {
33 FNode* Next = Tail->Next.load(std::memory_order_relaxed);
34
35 // sentinel's value is already destroyed
36 AllocatorType::Free(Tail);
37
38 while (Next != nullptr)
39 {
40 Tail = Next;
41 Next = Tail->Next.load(std::memory_order_relaxed);
42
43 DestructItem((ElementType*)&Tail->Value);
44 AllocatorType::Free(Tail);
45 }
46 }
47
48 template <typename... ArgTypes>
49 void Enqueue(ArgTypes&&... Args)
50 {
51 FNode* New = ::new(AllocatorType::Malloc(sizeof(FNode), alignof(FNode))) FNode;
52 ::new ((void*)&New->Value) ElementType(Forward<ArgTypes>(Args)...);
53
54 FNode* Prev = Head.exchange(New, std::memory_order_acq_rel);
55 Prev->Next.store(New, std::memory_order_release);
56 }
57
59 {
60 FNode* Next = Tail->Next.load(std::memory_order_acquire);
61
62 if (Next == nullptr)
63 {
64 return {};
65 }
66
67 ElementType* ValuePtr = (ElementType*)&Next->Value;
69 DestructItem(ValuePtr);
70
71 AllocatorType::Free(Tail); // current sentinel
72
73 Tail = Next; // new sentinel
74 return Res;
75 }
76
78 {
80 if (LocalElement.IsSet())
81 {
83 return true;
84 }
85
86 return false;
87 }
88
89 // as there can be only one consumer, a consumer can safely "peek" the tail of the queue.
90 // returns a pointer to the tail if the queue is not empty, nullptr otherwise
91 // there's no overload with TOptional as it doesn't support references
93 {
94 FNode* Next = Tail->Next.load(std::memory_order_acquire);
95
96 if (Next == nullptr)
97 {
98 return nullptr;
99 }
100
101 return (ElementType*)&Next->Value;
102 }
103
104 [[nodiscard]] bool IsEmpty() const
105 {
106 return Tail->Next.load(std::memory_order_acquire) == nullptr;
107 }
108
109private:
110 struct FNode
111 {
112 std::atomic<FNode*> Next{ nullptr };
114 };
115
116private:
117 std::atomic<FNode*> Head; // accessed only by producers
118 /*alignas(PLATFORM_CACHE_LINE_SIZE) */FNode* Tail; // accessed only by consumer, hence should be on a different cache line than `Head`
119};
FORCEINLINE constexpr void DestructItem(ElementType *Element)
Definition MemoryOps.h:56
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
T * New(FMemStackBase &Mem, int32 Count=1, int32 Align=DEFAULT_ALIGNMENT)
Definition MemStack.h:259
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTempIfPossible(T &&Obj) noexcept
Definition UnrealTemplate.h:538
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
Definition MpscQueue.h:18
bool IsEmpty() const
Definition MpscQueue.h:104
~TMpscQueue()
Definition MpscQueue.h:31
TOptional< ElementType > Dequeue()
Definition MpscQueue.h:58
UE_NONCOPYABLE(TMpscQueue)
T ElementType
Definition MpscQueue.h:20
bool Dequeue(ElementType &OutElem)
Definition MpscQueue.h:77
ElementType * Peek() const
Definition MpscQueue.h:92
TMpscQueue()
Definition MpscQueue.h:24
void Enqueue(ArgTypes &&... Args)
Definition MpscQueue.h:49
Definition Optional.h:131
Definition TypeCompatibleBytes.h:24