-
-
Save vgvgvvv/044550de0e68d4dbf346fe87449e93f0 to your computer and use it in GitHub Desktop.
Long Running Async Lambdas, lock-free (UE4)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Convenience Wrapper functions | |
//Using TaskGraph | |
FGraphEventRef RunLambdaOnGameThread(TFunction< void()> InFunction) | |
{ | |
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::GameThread); | |
} | |
FGraphEventRef RunLambdaOnAnyThread(TFunction< void()> InFunction) | |
{ | |
return FFunctionGraphTask::CreateAndDispatchWhenReady(InFunction, TStatId(), nullptr, ENamedThreads::AnyThread); | |
} | |
//Uses proper threading, for any task that may run longer than about 2 seconds. | |
void RunLongLambdaOnAnyThread(TFunction< void()> InFunction) | |
{ | |
FLambdaRunnable::RunLambdaOnBackGroundThread(InFunction); | |
} | |
//Example use case | |
//Run your code | |
RunLongLambdaOnAnyThread([] { | |
//Your off-thread code here, if you access data here, make sure you make an immutable copy (e.g. const) | |
... | |
//Assume you got some results you want to pass back | |
FString someResults = FString(TEXT("some data results")); | |
//copy data | |
const FString safeResultString = someResults | |
//pass results back to game thread | |
RunLambdaOnGameThread([pathString] { | |
//Do something with your results | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "ZipUtilityPrivatePCH.h" | |
#include "LambdaRunnable.h" | |
uint64 FLambdaRunnable::ThreadNumber = 0; | |
FLambdaRunnable::FLambdaRunnable(TFunction< void()> InFunction) | |
{ | |
FunctionPointer = InFunction; | |
Finished = false; | |
Number = ThreadNumber; | |
FString threadStatGroup = FString::Printf(TEXT("FLambdaRunnable%d"), ThreadNumber); | |
Thread = FRunnableThread::Create(this, *threadStatGroup, 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more | |
ThreadNumber++; | |
} | |
FLambdaRunnable::~FLambdaRunnable() | |
{ | |
delete Thread; | |
Thread = NULL; | |
} | |
//Init | |
bool FLambdaRunnable::Init() | |
{ | |
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Init"), Number); | |
return true; | |
} | |
//Run | |
uint32 FLambdaRunnable::Run() | |
{ | |
if (FunctionPointer) | |
FunctionPointer(); | |
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Run complete"), Number); | |
return 0; | |
} | |
//stop | |
void FLambdaRunnable::Stop() | |
{ | |
Finished = true; | |
} | |
void FLambdaRunnable::Exit() | |
{ | |
Finished = true; | |
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable %d Exit"), Number); | |
//delete ourselves when we're done | |
delete this; | |
} | |
void FLambdaRunnable::EnsureCompletion() | |
{ | |
Stop(); | |
Thread->WaitForCompletion(); | |
} | |
FLambdaRunnable* FLambdaRunnable::RunLambdaOnBackGroundThread(TFunction< void()> InFunction) | |
{ | |
FLambdaRunnable* Runnable; | |
if (FPlatformProcess::SupportsMultithreading()) | |
{ | |
Runnable = new FLambdaRunnable(InFunction); | |
//UE_LOG(LogClass, Log, TEXT("FLambdaRunnable RunLambdaBackGroundThread")); | |
return Runnable; | |
} | |
else | |
{ | |
return nullptr; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
/* | |
Long duration lambda wrapper, which are generally not supported by the taskgraph system. New thread per lambda and they will auto-delete upon | |
completion. | |
*/ | |
class FLambdaRunnable : public FRunnable | |
{ | |
private: | |
/** Thread to run the worker FRunnable on */ | |
FRunnableThread* Thread; | |
uint64 Number; | |
//Lambda function pointer | |
TFunction< void()> FunctionPointer; | |
/** Use this thread-safe boolean to allow early exits for your threads */ | |
FThreadSafeBool Finished; | |
//static TArray<FLambdaRunnable*> Runnables; | |
static uint64 ThreadNumber; | |
public: | |
//~~~ Thread Core Functions ~~~ | |
//Constructor / Destructor | |
FLambdaRunnable(TFunction< void()> InFunction); | |
virtual ~FLambdaRunnable(); | |
// Begin FRunnable interface. | |
virtual bool Init(); | |
virtual uint32 Run(); | |
virtual void Stop(); | |
virtual void Exit() override; | |
// End FRunnable interface | |
/** Makes sure this thread has stopped properly */ | |
void EnsureCompletion(); | |
/* | |
Runs the passed lambda on the background thread, new thread per call | |
*/ | |
static FLambdaRunnable* RunLambdaOnBackGroundThread(TFunction< void()> InFunction); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment