如何在UE4中创建线程
FRunnable和FRunnableThread方法對于大多數(shù)問題來說無疑是一個(gè)可行的解決方案。 但是,在創(chuàng)建許多任務(wù)時(shí),您可能會(huì)達(dá)到CPU可以處理的并發(fā)上限,此時(shí)并發(fā)線程實(shí)際上會(huì)在爭用CPU時(shí)間時(shí)相互阻礙。 然后可能值得查看FQueuedThreadPool以限制任務(wù)可用的線程數(shù)。
虛幻引擎4還提供了全局GThreadPool ,但是此線程池僅設(shè)置為單個(gè)線程(UE4.14.3)。 它似乎只是為了在另一個(gè)核心上運(yùn)行并發(fā)任務(wù)。
下面的代碼是什么
- 創(chuàng)建一個(gè)線程來計(jì)算前50,000個(gè)素?cái)?shù)
- 將增量完成數(shù)據(jù)發(fā)送回游戲線程
- 具有靜態(tài)訪問器,用于啟動(dòng),關(guān)閉和查找線程是否已完成。
靜態(tài)函數(shù)
您將在下面的代碼中注意到我使用靜態(tài)函數(shù)輕松啟動(dòng)新線程,如果我需要匆忙關(guān)閉線程(例如播放器退出),我也可以使用GameThread中的靜態(tài)Shutdown()函數(shù)游戲)
性能
我首先使用任務(wù)圖系統(tǒng)計(jì)算前50,000個(gè)素?cái)?shù),并創(chuàng)建50,000個(gè)任務(wù)(每個(gè)素?cái)?shù)找1個(gè))。
在本教程中看到的代碼中,我創(chuàng)建了一個(gè)專用線程來計(jì)算前50,000個(gè)素?cái)?shù)!
性能優(yōu)勢是非凡的!
我的fps在下面的代碼中為這個(gè)線程的整個(gè)運(yùn)行保持穩(wěn)定90(我選擇的最大fps)。
而對于任務(wù)圖系統(tǒng),當(dāng)我接近50,000時(shí),fps下降了最多40。
對于較大的任務(wù),請務(wù)必嘗試實(shí)際的多線程!
.H
//~~~~~ Multi Threading ~~~ class FPrimeNumberWorker : public FRunnable { /** Singleton instance, can access the thread any time via static accessor, if it is active! */static FPrimeNumberWorker* Runnable;/** Thread to run the worker FRunnable on */FRunnableThread* Thread;/** The Data Ptr */TArray<uint32>* PrimeNumbers;/** The PC */AVictoryGamePlayerController* ThePC;/** Stop this thread? Uses Thread Safe Counter */FThreadSafeCounter StopTaskCounter;//The actual finding of prime numbersint32 FindNextPrimeNumber();private:int32 PrimesFoundCount; public:int32 TotalPrimesToFind;//Done?bool IsFinished() const{return PrimesFoundCount >= TotalPrimesToFind;}//~~~ Thread Core Functions ~~~//Constructor / DestructorFPrimeNumberWorker(TArray<uint32>& TheArray, const int32 IN_PrimesToFindPerTick, AVictoryGamePlayerController* IN_PC);virtual ~FPrimeNumberWorker();// Begin FRunnable interface.virtual bool Init();virtual uint32 Run();virtual void Stop();// End FRunnable interface/** Makes sure this thread has stopped properly */void EnsureCompletion();//~~~ Starting and Stopping Thread ~~~/* Start the thread and the worker from static (easy access)! This code ensures only 1 Prime Number thread will be able to run at a time. This function returns a handle to the newly started instance.*/static FPrimeNumberWorker* JoyInit(TArray<uint32>& TheArray, const int32 IN_TotalPrimesToFind, AVictoryGamePlayerController* IN_PC);/** Shuts down the thread. Static so it can easily be called from outside the thread context */static void Shutdown();static bool IsThreadFinished();};.CPP
//*********************************************************** //Thread Worker Starts as NULL, prior to being instanced // This line is essential! Compiler error without it FPrimeNumberWorker* FPrimeNumberWorker::Runnable = NULL; //***********************************************************FPrimeNumberWorker::FPrimeNumberWorker(TArray<uint32>& TheArray, const int32 IN_TotalPrimesToFind, AVictoryGamePlayerController* IN_PC): ThePC(IN_PC), TotalPrimesToFind(IN_TotalPrimesToFind), StopTaskCounter(0), PrimesFoundCount(0) {//Link to where data should be storedPrimeNumbers = &TheArray;Thread = FRunnableThread::Create(this, TEXT("FPrimeNumberWorker"), 0, TPri_BelowNormal); //windows default = 8mb for thread, could specify more }FPrimeNumberWorker::~FPrimeNumberWorker() {delete Thread;Thread = NULL; }//Init bool FPrimeNumberWorker::Init() {//Init the Data PrimeNumbers->Empty();PrimeNumbers->Add(2);PrimeNumbers->Add(3);if(ThePC) {ThePC->ClientMessage("**********************************");ThePC->ClientMessage("Prime Number Thread Started!");ThePC->ClientMessage("**********************************");}return true; }//Run uint32 FPrimeNumberWorker::Run() {//Initial wait before startingFPlatformProcess::Sleep(0.03);//While not told to stop this thread // and not yet finished finding Prime Numberswhile (StopTaskCounter.GetValue() == 0 && ! IsFinished()){PrimeNumbers->Add(FindNextPrimeNumber());PrimesFoundCount++;//***************************************//Show Incremental Results in Main Game Thread!// Please note you should not create, destroy, or modify UObjects here.// Do those sort of things after all thread are completed.// All calcs for making stuff can be done in the threads// But the actual making/modifying of the UObjects should be done in main game thread.ThePC->ClientMessage(FString::FromInt(PrimeNumbers->Last()));//***************************************//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//prevent thread from using too many resources//FPlatformProcess::Sleep(0.01);//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}//Run FPrimeNumberWorker::Shutdown() from the timer in Game Thread that is watching//to see when FPrimeNumberWorker::IsThreadFinished()return 0; }//stop void FPrimeNumberWorker::Stop() {StopTaskCounter.Increment(); }FPrimeNumberWorker* FPrimeNumberWorker::JoyInit(TArray<uint32>& TheArray, const int32 IN_TotalPrimesToFind, AVictoryGamePlayerController* IN_PC) {//Create new instance of thread if it does not exist// and the platform supports multi threading!if (!Runnable && FPlatformProcess::SupportsMultithreading()){Runnable = new FPrimeNumberWorker(TheArray,IN_TotalPrimesToFind,IN_PC); }return Runnable; }void FPrimeNumberWorker::EnsureCompletion() {Stop();Thread->WaitForCompletion(); }void FPrimeNumberWorker::Shutdown() {if (Runnable){Runnable->EnsureCompletion();delete Runnable;Runnable = NULL;} }bool FPrimeNumberWorker::IsThreadFinished() {if(Runnable) return Runnable->IsFinished();return true; } int32 FPrimeNumberWorker::FindNextPrimeNumber() {//Last known prime number + 1int32 TestPrime = PrimeNumbers->Last();bool NumIsPrime = false;while( ! NumIsPrime){NumIsPrime = true;//Try Next NumberTestPrime++;//Modulus from 2 to current number - 1 for(int32 b = 2; b < TestPrime; b++){//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//prevent thread from using too many resources//FPlatformProcess::Sleep(0.01);//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~if(TestPrime % b == 0) {NumIsPrime = false;break;//~~~}}}//Success!return TestPrime; }Starting the thread
//In the .h for the player controller // this is the actual data TArray<uint32> PrimeNumbers;?
//player controller .cpp //Multi-threading, returns handle that could be cached. // use static function FPrimeNumberWorker::Shutdown() if necessary FPrimeNumberWorker::JoyInit(PrimeNumbers, 50000, this);線程管理
您應(yīng)該查看“FRunnable”的代碼庫,以查看多線程和鎖定/解鎖保護(hù)的擴(kuò)展用途。
我用了一個(gè)簡單的例子來幫助你入門,但是多線程時(shí)需要考慮很多:)
使用Sleep進(jìn)行線程管理
你應(yīng)該考慮使用
FPlatformProcess :: Sleep ( 秒 );防止1個(gè)線程占用太多系統(tǒng)資源:)
什么不該做
- 不要嘗試從其他線程修改,創(chuàng)建或刪除UObject!
您可以準(zhǔn)備所有數(shù)據(jù)/進(jìn)行所有計(jì)算,但只有游戲線程應(yīng)該實(shí)際產(chǎn)生/修改/刪除UObjects / AActors。
- 不要嘗試在游戲線程之外使用TimerManager :)
- 不要試圖繪制調(diào)試行/點(diǎn)等,因?yàn)樗赡軙?huì)崩潰,即DrawDebugLine(等...)
-
通知(自4.11起):
如果要使用計(jì)時(shí)器,刪除和修改變量,請使用它:
#include “Async.h” ...AsyncTask ( ENamedThreads :: GameThread , []() {//這里在游戲線程上執(zhí)行的代碼});GameThread中的計(jì)時(shí)器功能
您可以在游戲線程中運(yùn)行計(jì)時(shí)器功能,以定期檢查您創(chuàng)建的其他線程收集的數(shù)據(jù)。
如何支持單線程平臺?
如果您的代碼絕對必須在HTML5等單線程環(huán)境中運(yùn)行,那么請查看
AsyncIOSystemBase.h
struct CORE_API FAsyncIOSystemBase:public FIOSystem,FRunnable,FSingleThreadRunnableRunnable可以擴(kuò)展SingleThreadRunnable,并為單線程情況下的FRunnable鉤子返回自己:
總結(jié)
以上是生活随笔為你收集整理的如何在UE4中创建线程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广发银泰联名信用卡申请条件及方法
- 下一篇: OpenDrive记录