#include"Async/AsyncWork.h"classPrimeCalculationAsyncTask:public FNonAbandonableTask
{
int32 MaxPrime;public:/*Default constructor*/PrimeCalculationAsyncTask(int32 MaxPrime){this->MaxPrime = MaxPrime;}/*This function is needed from the API of the engine.
My guess is that it provides necessary information
about the thread that we occupy and the progress of our task*/
FORCEINLINE TStatId GetStatId()const{RETURN_QUICK_DECLARE_CYCLE_STAT(PrimeCalculationAsyncTask, STATGROUP_ThreadPoolAsyncTasks);}/*This function is executed when we tell our task to execute*/voidDoWork(){//TODO:具体耗时的任务 }};//完成后自动删除操作auto task =new FAutoDeleteAsyncTask<PrimeCalculationAsyncTask>(MaxPrime);if(task){
task ->StartBackgroundTask();}
FRunnable
classFPrimeNumberWorker:public FRunnable
{/** Singleton instance, can access the thread any time via static accessor, if it is active! */static FPrimeNumberWorker* CRunnable;/** Thread to run the worker FRunnable on */
FRunnableThread* Thread;/** The Data Ptr */
TArray<uint32>* PrimeNumbers;/** Stop this thread? Uses Thread Safe Counter */
FThreadSafeCounter StopTaskCounter;//The actual finding of prime numbers
int32 FindNextPrimeNumber();private:
int32 PrimesFoundCount;//Constructor / DestructorFPrimeNumberWorker(TArray<uint32>& TheArray,const int32 IN_PrimesToFindPerTick);virtual~FPrimeNumberWorker();public:
int32 TotalPrimesToFind;//Done?boolIsFinished()const{return PrimesFoundCount >= TotalPrimesToFind;}//~~~ Thread Core Functions ~~~// Begin FRunnable interface.virtualboolInit();virtual uint32 Run();virtualvoidStop();// End FRunnable interface/** Makes sure this thread has stopped properly */voidEnsureCompletion();//~~~ 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);/** Shuts down the thread. Static so it can easily be called from outside the thread context */staticvoidShutdown();staticboolIsThreadFinished();};
#include"PrimeNumberWorker.h"
int32 FPrimeNumberWorker::FindNextPrimeNumber(){//Last known prime number + 1
int32 TestPrime = PrimeNumbers->Last();bool NumIsPrime =false;while(!NumIsPrime){
NumIsPrime =true;//Try Next Number
TestPrime++;//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;}
FPrimeNumberWorker::FPrimeNumberWorker(TArray<uint32>& TheArray,const int32 IN_PrimesToFindPerTick):TotalPrimesToFind(IN_PrimesToFindPerTick),StopTaskCounter(0),PrimesFoundCount(0){//Link to where data should be stored
PrimeNumbers =&TheArray;
Thread = FRunnableThread::Create(this,TEXT("FPrimeNumberWorker"),0, TPri_BelowNormal);//windows default = 8mb for thread, could specify more}
FPrimeNumberWorker::~FPrimeNumberWorker(){delete Thread;
Thread =NULL;}bool FPrimeNumberWorker::Init(){
PrimeNumbers->Empty();
PrimeNumbers->Add(2);
PrimeNumbers->Add(3);returntrue;}
uint32 FPrimeNumberWorker::Run(){//Initial wait before starting
FPlatformProcess::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++;
FPlatformProcess::Sleep(0.01);}return0;}void FPrimeNumberWorker::Stop(){
StopTaskCounter.Increment();}void FPrimeNumberWorker::EnsureCompletion(){Stop();
Thread->WaitForCompletion();}
FPrimeNumberWorker* FPrimeNumberWorker::JoyInit(TArray<uint32>& TheArray,const int32 IN_TotalPrimesToFind){if(!CRunnable && FPlatformProcess::SupportsMultithreading()){
CRunnable =newFPrimeNumberWorker(TheArray, IN_TotalPrimesToFind);}return CRunnable;}void FPrimeNumberWorker::Shutdown(){if(CRunnable){
CRunnable->EnsureCompletion();delete CRunnable;
CRunnable =NULL;}}bool FPrimeNumberWorker::IsThreadFinished(){if(CRunnable)return CRunnable->IsFinished();returntrue;}