如何在UE4中创建线程
FRunnable和FRunnableThread方法對于大多數問題來說無疑是一個可行的解決方案。 但是,在創建許多任務時,您可能會達到CPU可以處理的并發上限,此時并發線程實際上會在爭用CPU時間時相互阻礙。 然后可能值得查看FQueuedThreadPool以限制任務可用的線程數。
虛幻引擎4還提供了全局GThreadPool ,但是此線程池僅設置為單個線程(UE4.14.3)。 它似乎只是為了在另一個核心上運行并發任務。
下面的代碼是什么
- 創建一個線程來計算前50,000個素數
- 將增量完成數據發送回游戲線程
- 具有靜態訪問器,用于啟動,關閉和查找線程是否已完成。
靜態函數
您將在下面的代碼中注意到我使用靜態函數輕松啟動新線程,如果我需要匆忙關閉線程(例如播放器退出),我也可以使用GameThread中的靜態Shutdown()函數游戲)
性能
我首先使用任務圖系統計算前50,000個素數,并創建50,000個任務(每個素數找1個)。
在本教程中看到的代碼中,我創建了一個專用線程來計算前50,000個素數!
性能優勢是非凡的!
我的fps在下面的代碼中為這個線程的整個運行保持穩定90(我選擇的最大fps)。
而對于任務圖系統,當我接近50,000時,fps下降了最多40。
對于較大的任務,請務必嘗試實際的多線程!
.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);線程管理
您應該查看“FRunnable”的代碼庫,以查看多線程和鎖定/解鎖保護的擴展用途。
我用了一個簡單的例子來幫助你入門,但是多線程時需要考慮很多:)
使用Sleep進行線程管理
你應該考慮使用
FPlatformProcess :: Sleep ( 秒 );防止1個線程占用太多系統資源:)
什么不該做
- 不要嘗試從其他線程修改,創建或刪除UObject!
您可以準備所有數據/進行所有計算,但只有游戲線程應該實際產生/修改/刪除UObjects / AActors。
- 不要嘗試在游戲線程之外使用TimerManager :)
- 不要試圖繪制調試行/點等,因為它可能會崩潰,即DrawDebugLine(等...)
-
通知(自4.11起):
如果要使用計時器,刪除和修改變量,請使用它:
#include “Async.h” ...AsyncTask ( ENamedThreads :: GameThread , []() {//這里在游戲線程上執行的代碼});GameThread中的計時器功能
您可以在游戲線程中運行計時器功能,以定期檢查您創建的其他線程收集的數據。
如何支持單線程平臺?
如果您的代碼絕對必須在HTML5等單線程環境中運行,那么請查看
AsyncIOSystemBase.h
struct CORE_API FAsyncIOSystemBase:public FIOSystem,FRunnable,FSingleThreadRunnableRunnable可以擴展SingleThreadRunnable,并為單線程情況下的FRunnable鉤子返回自己:
總結
以上是生活随笔為你收集整理的如何在UE4中创建线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广发银泰联名信用卡申请条件及方法
- 下一篇: OpenDrive记录