There seems to be no unified way in which each async method executes its tasks and allocates its memory.
I did have some success recently with FRunnable. I won’t post all of the code as it’s too long but here is the creation code:
class FMyNewRunTask : public FRunnable
{
protected:
FRunnableThread* Thread; //Thread to run the worker on
FThreadSafeCounter StopTaskCounter; //Thread safe counter to stop the thread
public:
FMyNewRunTask(FOnCompletion* InCompleteCallback, bool* bInTaskCompleted)
: Thread(nullptr)
, StopTaskCounter(0)
, CompleteCallback(InCompleteCallback)
, bTaskCompleted(bInTaskCompleted)
{
UE_LOG(LogTemp, Error, TEXT("Task Constructor"));
MyNewDataObject = new FMyNewDataObject();
}
~FMyNewRunTask()
{
delete MyNewDataObject;
MyNewDataObject = nullptr;
UE_LOG(LogTemp, Error, TEXT("Task Destructor"));
}
then when I want my “Complete Callback” to trigger I use the below code from with the Run() function at the end of processing:
AsyncTask(ENamedThreads::GameThread, [this]()
{
if (this)
{
if (CompleteCallback->IsBound())
{
CompleteCallback->Execute(MyNewDataObject);
}
}
});
int32 LoopCounter = 0;
//Wait for the callback to finish
do
{
//...waiting
FPlatformProcess::Sleep(0.1f);
LoopCounter++;
} while ((*bTaskCompleted) == false || LoopCounter > 100.f /*10 seconds to stop endless loop*/);
The delegate is:
DECLARE_DELEGATE_OneParam(FOnCompletion, FMyNewDataObject*);
I then empty the MyNewDataObject struct on the thread exit().
The main variables are:
bool* bTaskCompleted = nullptr;
FMyNewDataObject* MyNewDataObject;
FOnCompletion* CompleteCallback;
To run the FRunnable class from the main actor I use:
void AMyActor::DoRunnableSomething()
{
StopTask(); //This function stops the thread if it was run before and deletes it ready for restarting
if (!MyNewOnCompletion.IsBound())
{
MyNewOnCompletion = FOnCompletion::CreateUObject(this, &AMyActor::MyNewCompletionFunction);
}
bTaskComplete = false;
RunTaskWorker = new FMyNewRunTask(&MyNewOnCompletion, &bTaskComplete);
RunTaskWorker->Startup();
}
The complete callback calls this:
void AMyActor::MyNewCompletionFunction(FMyNewDataObject* TheData)
{
TheMainDataObject = *TheData; //This dereferences and copies the data
bTaskComplete = true;
}
The end result at the moment for me is that the data inside the async task produces its data and posts back it pointer to its data. The main actor then copies the data and does what it wants with it. The async object is then free to delete its own version of the data.
To delete the data I use this:
void AMyActor::Destroyed()
{
//Empty whatever the struct contains
TheMainDataObject.TheIntArray.Empty();
TheMainDataObject.TheFloatArray.Empty();
TheMainDataObject.TheStructArray.Empty();
StopTask(); //Stops the thread worker if it exists and deletes it
UE_LOG(LogTemp, Warning, TEXT("Actor got Destroyed!"));
Super::Destroyed();
}
I have hammered away at this for the last month so I am pretty tired of it now. The code right now works so 
Parts that I am not quite understanding is how I am supposed to delete the async task after the callback has triggerd because if you don’t do the “Do…While” then the task deletes before the callback has been called.
All opinions are welcome.
Thanks.