I’m looking to offload some work to another thread and stumbled upon [this post in written in early 2015](New Core Feature: Async Framework (Master Branch and 4.8) - Engine Source & GitHub - Unreal Engine Forums. It discusses using the Async template class to have functions dispatched to other threads/tasks/pools. Even with the author putting what appears to be a lot of time in his post, I can’t get it working and have to ask two questions:
Is this the recommended way to get member functions running on a different thread?
Can someone show me an example of how to get this running?
SimpleClass.h
class SimpleClass : public AActor
{
//...
public:
void MyWorkerFunction();
protected:
virtual void Tick(float DeltaTime) override;
}
SimpleClass.cpp
#include "Async.h"
// other includes...
void SimpleClass::Tick(float DeltaTime)
{
// create delegate/thread/async call here
Async<void>(EAsyncExecution::TaskGraph, MyWorkerFunction()); // compiler: no instance of function template "Async" matches the argument list
}
void SimpleClass::MyWorkerFunction()
{
// I want my work done here on a separate thread
}
My worker function is of type void so I don’t care about return values or using TFuture. What is the proper way to get a member function running on a different thread?
The lambda should work - it needs a *TFunction<void()>, *and a lambda is generally the simplest way to construct one.
You need to be very careful with what you’re doing though. First off, starting an async task on every tick is questionable in terms of whether it’s going to give you any performance gain.
More importantly though, you’re calling a member function of a UObject. UObjects are in general not threadsafe, so there is very little that you can safely do inside MyWorkerFunction without creating a race condition, even if you can guarantee the object itself won’t get destroyed.
To safely do something on a background thread in UE4, you generally need to grab a copy of whatever raw data you need to work on from the game thread, pass that to the task, then when the task is done it notifies the game thread of its results, which can then sync those results to game objects as necessary.
The lambda did indeed work. I created the above example to be as simple as possible. I actually have a conditional around the Async call that only gets called under certain circumstances - at most it can only be called once every 4 seconds.
That being said, after reading your post, I’m now considering changing things around and using an AsyncTask. Originally I wanted to avoid carving out all the logic from my actor and moving it to the new class, but the further down this road I get, the more it makes since to keep it isolated and organized.
I just realized that I’m not able to SpawnActor on a background thread. Makes sense now that I think about it. However, I’m creating a procedural terrain and each actor is a chunk of that terrain. The building of the actor is computationally heavy since I’m using several noise functions.
Looks like I need to redesign the way I build the world, sigh.