Skip to content

Instantly share code, notes, and snippets.

@vgvgvvv
Forked from getnamo/Examples.cpp
Created Jan 19, 2021
Embed
What would you like to do?
Long Running Async Lambdas, lock-free (UE4)
//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
});
});
#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;
}
}
#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