I’m having a problem when using multithreading in UE4. I’m designing a module in a VR project that receives data from VR devices to calculate the player’s position in the real world to correct the player’s position in the game. Since this operation is very computationally intensive (needs 2-3 sec on my PC), I opened a new thread (FRunnableThread
) dedicated to it. See the second thread part in the following image:
However, during the test, my main game thread would get stuck until the second thread finished calculating. With the log file, I can confirm that I did open the second thread.
Is this because the main thread of the game is waiting to sync with the second thread? If I want the player to still be able to move around the game while the second thread is doing the calculations, how can I do that?
// head file
UCLASS()
class OPENCV_API ALoadDoorCornerCoords : public AActor
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable, Category = LoadCSV, meta = (Keywords = "Load Door Corners", NativeBreakFunc))
TArray<FVector2D> LoadCorners();
public:
// Sets default values for this actor's properties
ALoadDoorCornerCoords();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
class FLoadCorners :public FRunnable
{
public:
FLoadCorners();
~FLoadCorners();
TArray<FVector2D> corners;
class FRunnableThread* MyLoadCornersThread;
static FLoadCorners* MyLoadCorners;
static void JoyInit();
static void Shutdown();
FCriticalSection m_mutex;
static int runCount1;
private:
virtual bool Init() override;
virtual uint32 Run() override;
virtual void Stop() override;
virtual void Exit() override;
};
LoadCornersProcess()
in the cpp file is the function used to get the player’s position.
// cpp file
FLoadCorners* FLoadCorners::MyLoadCorners = nullptr;
FLoadCorners::FLoadCorners()
{
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Add Instance"));
MyLoadCornersThread = FRunnableThread::Create(this, TEXT("MyLoadCornersRunnableThread"));
if (MyLoadCorners != nullptr) {
delete MyLoadCorners;
MyLoadCorners = nullptr;
}
}
FLoadCorners::~FLoadCorners()
{
delete MyLoadCornersThread;
MyLoadCornersThread = nullptr;
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Del Instance"));
}
bool FLoadCorners::Init() {
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Init"));
return true;
}
void FLoadCorners::JoyInit()
{
if (FPlatformProcess::SupportsMultithreading())
{
MyLoadCorners = new FLoadCorners();
}
}
uint32 FLoadCorners::Run()
{
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Run"));
UE_LOG(LogTemp, Warning, TEXT("Current Thread ID: %s"), *FString::FromInt(FPlatformTLS::GetCurrentThreadId()));
FLoadCorners::corners = TArray<FVector2D>();
FLoadCorners::corners = LoadCornersProcess();
FString arrayLens = FString::FromInt(FLoadCorners::corners.Num());
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Result Lenth: %s"), *arrayLens);
return 0;
}
void FLoadCorners::Stop()
{
MyLoadCornersThread->WaitForCompletion();
UE_LOG(LogTemp, Warning, TEXT("MyLoadCorners Stop"));
}
void FLoadCorners::Exit() {
UE_LOG(LogTemp, Warning, TEXT("MyFindVertices Exit"));
}
void FLoadCorners::Shutdown()
{
MyLoadCorners->Stop();
MyLoadCorners->~FLoadCorners();
}
// Sets default values
ALoadDoorCornerCoords::ALoadDoorCornerCoords()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
}
// Called when the game starts or when spawned
void ALoadDoorCornerCoords::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ALoadDoorCornerCoords::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
int FLoadCorners::runCount1 = 0;
TArray<FVector2D> ALoadDoorCornerCoords::LoadCorners()
{
UE_LOG(LogTemp, Warning, TEXT("Current Thread ID: %s"), *FString::FromInt(FPlatformTLS::GetCurrentThreadId()));
FLoadCorners::JoyInit();
FLoadCorners::Shutdown();
FLoadCorners::runCount1++;
UE_LOG(LogTemp, Warning, TEXT("Current Thread ID: %s"), *FString::FromInt(FPlatformTLS::GetCurrentThreadId()));
return FLoadCorners::MyLoadCorners->corners;
}