[UE4][multi-thread]如何创建和终止线程:FRunnableThread::Create()

关键字:UE4 多线程

原文:https://wiki.unrealengine.com/Multi-Threading:_How_to_Create_Threads_in_UE4

相关文档

FRunnable

https://docs.unrealengine.com/latest/INT/API/Runtime/Core/HAL/FRunnable/index.html

FRunnableThread

https://docs.unrealengine.com/latest/INT/API/Runtime/Core/HAL/FRunnableThread/index.html

 

 

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 numbers
	int32 FindNextPrimeNumber();
 
private:
	int32				PrimesFoundCount;
public:
 
	int32				TotalPrimesToFind;
 
	//Done?
	bool IsFinished() const
	{
		return PrimesFoundCount >= TotalPrimesToFind;
	}
 
	//~~~ Thread Core Functions ~~~
 
	//Constructor / Destructor
	FPrimeNumberWorker(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 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;
}
 
//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 starting
	FPlatformProcess::Sleep(0.03);
 
	//While not told to stop this thread 
	//		and not yet finished finding Prime Numbers
	while (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  + 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;
}

 

以上是完成了一个继承自FRunnable的自定义类,那么如何用这个类启动线程:

1,这个例子需要一个数组,那么现在头文件中定义一个测试用的变量

//In the .h for the player controller
// this is the actual data
TArray<uint32> PrimeNumbers;

 2,创建并启动线程:

//player controller .cpp
//Multi-threading, returns handle that could be cached.
//		use static function FPrimeNumberWorker::Shutdown() if necessary
FPrimeNumberWorker::JoyInit(PrimeNumbers, 50000, this);

 

补充:

结束终止线程

 

void FPrimeNumberWorker::EnsureCompletion()  
{  
    Stop();  
    Thread->WaitForCompletion();  
}
 

 

猜你喜欢

转载自aigo.iteye.com/blog/2288950