Can I create an Actor object in a thread other than the GameThread Thread?

// .h 
class TIPS_API FSimpleRunnable: public FRunnable
{
public:
	FSimpleRunnable(const FString& ThreadName);
	~FSimpleRunnable();
	void PauseThread();					
	void WakeUpThread();			
	void Suspend(bool bSuspend);	
	void StopThread();				
	void ShutDown(bool bShouldWait);

private:
	FString m_ThreadName;
	int32 m_ThreadID;
	bool bRun = true;				
	bool bPause = false;			
	FRunnableThread* ThreadIns;		
	FEvent* ThreadEvent;			

	virtual bool Init() override;
	virtual uint32 Run() override;
	virtual void Stop() override;
	virtual void Exit() override;
};

I would guess probably not, you’d probably need to set a flag to the gamethread to do the spawn there. I could be wrong, though.

Generally no. But you can use the AsyncTask function from your thread to push some functionality to happen on GameThread:

void ThisFunctionRunsOnADifferentThread()
{
	// Do lots of slow thread stuff here.

	int SendMeToGameThread = 1337;

	AsyncTask(ENamedThreads::GameThread, [SendMeToGameThread ],
	{
		// Do whatever you need to do on the gamethread here.
		// Use `SendMeToGameThread` or any other variables you created in the thread through the [brackets] above.

	});
}
2 Likes

Will,Is this ublueprintAsyncactionbase also multithreaded?

Hello, is the following FNonAbandonableTask implementation correct?

class AsyncTracer : public FNonAbandonableTask
{
public:
UAxisSearcher* SearcherCaller;

public:
AsyncTracer(UAxisSearcher* InSearcher);
~AsyncTracer();

FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(AsyncTracer, STATGROUP_ThreadPoolAsyncTasks); }

void DoWork();
};

AsyncTracer::AsyncTracer(UAxisSearcher* InSearcher)
	:SearcherCaller(InSearcher)
{
}

AsyncTracer::~AsyncTracer()
{
}

void AsyncTracer::DoWork()
{
        ...
	if (IsValid(SearcherCaller)) /*<- This validity check does not prevent the crash!*/
	{
		UE_LOG(LogTemp, Log, TEXT("About to call begin path finds on: %s"), *SearcherCaller->GetName()); /*<-This log is NEVER printed when the crash occurs!*/
		AsyncTask(ENamedThreads::GameThread, [=]() { SearcherCaller->BeginPathFinds(bAnyPointValid); } );
	}
}

Could SearcherCaller be garbage collected while your thread is running? That’s the biggest issue with doing threaded work, they won’t get notified if UObjects get garbage collected so usually our recommendation is to not touch any UObjects in threads, but just send plain data to the threads that they can work on. Then the thread can call back into the game thread with the AsyncTask function where it can do something with that data back in “UObject land”, i.e. the game thread.

If SearcherCaller gets garbage collected and that memory gets reused for something else, UAxisSearcher* SearcherCaller; won’t get nulled since the Garbage Collector doesn’t know of that property, then IsValid doesn’t really know if the object is a proper object since you’re just pointing to garbage data, and then it most likely crashes.

Thank you for your question and answer. Currently, we are developing network data driven vehicle movement. Do you have any good suggestions to improve the synchronization of vehicle and network data?

I unfortunately don’t have experience in that area.