Skip to content

Instantly share code, notes, and snippets.

@muit
Created January 13, 2019 22:55
Show Gist options
  • Save muit/65be03be1d3bac787831bc01a3e46e2a to your computer and use it in GitHub Desktop.
Save muit/65be03be1d3bac787831bc01a3e46e2a to your computer and use it in GitHub Desktop.
Keeps an array of multi-threaded tasks in order without memory leaks and with a nice syntax (in UE4)
// Copyright 2015-2019 Piperift. All Rights Reserved.
#pragma once
#include <Async/AsyncWork.h>
#include "Misc/TypeTraits.h"
class ITaskHolder {
public:
virtual bool Tick() = 0;
virtual void Cancel(bool bFinishSynchronously) = 0;
virtual ~ITaskHolder() {}
};
template<class TaskType>
class FTaskHolder : public FAsyncTask<TaskType>, public ITaskHolder {
using Super = FAsyncTask<TaskType>;
public:
DECLARE_EVENT_OneParam(FTaskHolder<TaskType>, FFinishedEvent, FTaskHolder<TaskType>&);
FFinishedEvent _OnFinished;
FTaskHolder() : ITaskHolder(), Super() {}
virtual ~FTaskHolder() {}
template <typename... ArgTypes>
FTaskHolder(ArgTypes&&... CtrArgs) : ITaskHolder(), Super(Forward<ArgTypes>(CtrArgs)...) {}
auto& OnFinished(TFunction<void(FTaskHolder<TaskType>&)> Delegate) {
_OnFinished.AddLambda(Delegate);
return *this;
}
virtual bool Tick() override {
if (Super::IsDone())
{
_OnFinished.Broadcast(*this);
return true;
}
return false;
}
virtual void Cancel(bool bFinishSynchronously) override {
if (!Super::IsIdle())
{
Super::EnsureCompletion(bFinishSynchronously);
_OnFinished.Broadcast(*this);
}
}
TaskType* operator->() {
return &Super::GetTask();
}
};
/** Manages the lifetime of many multi-threaded tasks */
class FScopedTaskList {
TArray<ITaskHolder*> Tasks;
public:
FScopedTaskList() {}
FScopedTaskList(FScopedTaskList&& other) {}
template<class TaskType, typename... ArgTypes>
inline FTaskHolder<TaskType>& CreateTask(ArgTypes&&... CtrArgs) {
auto* NewTask = new FTaskHolder<TaskType>(Forward<ArgTypes>(CtrArgs)...);
Tasks.Add(NewTask);
return *NewTask;
}
void Tick() {
// Tick all running tasks and remove the ones that finish
Tasks.RemoveAllSwap([](auto* Task) {
bool bFinished = Task->Tick();
if (bFinished)
delete Task;
return bFinished;
});
}
void CancelAll() {
for (auto* Task : Tasks)
{
Task->Cancel(false);
delete Task;
}
Tasks.Empty();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment