FRunnable and Threads

There are a bunch of ways to do threads in Unreal. Today we're going to cover
possibly the simplest one, FRunnable.

Our very simple example consists of two classes, UThreadManager that creates
a thread and runs it, and ThreadExample, that does some expensive processing.

I'll let the code and comments do most of the explaining.

ThreadManager.h

Create an instance of this and call StartProcess() on it, and call PrintStuff()
every frame to test out the example.

#pragma once
#include "ThreadManager.generated.h"
UCLASS()classUThreadManager:publicUObject{GENERATED_BODY()public:UThreadManager(constFObjectInitializer&ObjectInitializer);// Call this to create the thread and start it going
voidStartProcess();// Call this to print the current state of the thread
voidPrintStuff();protected:boolIsComplete()const;classThreadExample*MyThreadExample=nullptr;FRunnableThread*CurrentThread=nullptr;};

ThreadExample.h

#pragma once
#include "HAL/Runnable.h"
// Note that we do not have to mark our class as UCLASS() if we don't want to
classThreadExample:publicFRunnable{public:// Custom constructor for setting up our thread with its target
ThreadExample(int32InTargetCount);// FRunnable functions
virtualuint32Run()override;virtualvoidStop()override;virtualvoidExit()override;// FRunnable
TArray<int32>ProcessedNumbers;boolIsComplete()const;protected:int32TargetCount=-1;int32FoundCount=-1;boolbStopThread=false;};

ThreadExample.cpp

#include "MyProjectPCH.h"
#include "ThreadExample.h"
ThreadExample::ThreadExample(int32InTargetCount){TargetCount=InTargetCount;FoundCount=0;}uint32ThreadExample::Run(){bStopThread=false;// Keep processing until we're cancelled through Stop() or we're done,
// although this thread will suspended for other stuff to happen at the same time
while(!bStopThread&&!IsComplete()){// This is where we would do our expensive threaded processing
// Instead we're going to make a reaaaally busy while loop to slow down processing
// You can change INT_MAX to something smaller if you want it to run faster
int32x=0;while(x<INT_MAX){x++;}ProcessedNumbers.Add(FMath::RandRange(0,999));FoundCount+=1;}// Return success
return0;}voidThreadExample::Exit(){// Here's where we can do any cleanup we want to
}voidThreadExample::Stop(){// Force our thread to stop early
bStopThread=true;}boolThreadExample::IsComplete()const{returnFoundCount>=TargetCount;}