FRunnable
FRunnable是一个线程的接口,提供一些基本的函数Init,Run等,配合FRunnableThread创建执行线程。
/**
* Interface for "runnable" objects.
*
* A runnable object is an object that is "run" on an arbitrary thread. The call usage pattern is
* Init(), Run(), Exit(). The thread that is going to "run" this object always uses those calling
* semantics. It does this on the thread that is created so that any thread specific uses (TLS, etc.)
* are available in the contexts of those calls. A "runnable" does all initialization in Init().
*
* If initialization fails, the thread stops execution and returns an error code. If it succeeds,
* Run() is called where the real threaded work is done. Upon completion, Exit() is called to allow
* correct clean up.
*/
class CORE_API FRunnable
{
public:
/**
* Initializes the runnable object.
*
* This method is called in the context of the thread object that aggregates this, not the
* thread that passes this runnable to a new thread.
*
* @return True if initialization was successful, false otherwise
* @see Run, Stop, Exit
*/
virtual bool Init()
{
return true;
}
/**
* Runs the runnable object.
*
* This is where all per object thread work is done. This is only called if the initialization was successful.
*
* @return The exit code of the runnable object
* @see Init, Stop, Exit
*/
virtual uint32 Run() = 0;
/**
* Stops the runnable object.
*
* This is called if a thread is requested to terminate early.
* @see Init, Run, Exit
*/
virtual void Stop() { }
/**
* Exits the runnable object.
*
* Called in the context of the aggregating thread to perform any cleanup.
* @see Init, Run, Stop
*/
virtual void Exit() { }
/**
* Gets single thread interface pointer used for ticking this runnable when multi-threading is disabled.
* If the interface is not implemented, this runnable will not be ticked when FPlatformProcess::SupportsMultithreading() is false.
*
* @return Pointer to the single thread interface or nullptr if not implemented.
*/
virtual class FSingleThreadRunnable* GetSingleThreadInterface( )
{
return nullptr;
}
/** Virtual destructor */
virtual ~FRunnable() { }
};
FRunnableThread
继承自FRunnable接口的对象本身并没有执行能力,需要配合FRunnableThread来创建线程,然后执行线程函数。
FRunnableThread通过FRunnableThread::Create来调用对应平台的接口来创建线程,并调用 FRunnable 对象的Init,Run等事件。Create执行之后,对应的线程函数Run立即执行,并没有Start之类的方法。
各个函数的执行顺序是,首先执行Init,然后执行Run,Run执行完毕之后执行Exit。
如果要结束线程,可以调用FRunnableThread的Kill方法。Kill方法仅仅调用了RunnableObject的Stop方法,因此需要手动在Stop方法中将退出信息传递给Run函数,从而结束Run方法。
class MYPROJECT_API MyRunnableObject: public FRunnable
{
public:
MyRunnableObject();
virtual ~MyRunnableObject();
int RunTime = 0;
bool bIsRunning = false;
/**
* Initializes the runnable object.
*
* This method is called in the context of the thread object that aggregates this, not the
* thread that passes this runnable to a new thread.
*
* @return True if initialization was successful, false otherwise
* @see Run, Stop, Exit
*/
virtual bool Init()
{
bIsRunning = true;
UE_LOG(LogTemp, Display, TEXT("Init."));
return true;
}
/**
* Runs the runnable object.
*
* This is where all per object thread work is done. This is only called if the initialization was successful.
*
* @return The exit code of the runnable object
* @see Init, Stop, Exit
*/
virtual uint32 Run()
{
while (bIsRunning)
{
UE_LOG(LogTemp, Display, TEXT("Run %d."), RunTime);
++RunTime;
//频繁打印日志会导致游戏线程卡死!
FPlatformProcess::Sleep(1);
}
return 0;
}
/**
* Stops the runnable object.
*
* This is called if a thread is requested to terminate early.
* @see Init, Run, Exit
*/
virtual void Stop()
{
UE_LOG(LogTemp, Display, TEXT("Kill is called via FRunnableThread, stop now."));
bIsRunning = false;
}
/**
* Exits the runnable object.
*
* Called in the context of the aggregating thread to perform any cleanup.
* @see Init, Run, Stop
*/
virtual void Exit()
{
UE_LOG(LogTemp, Display, TEXT("Run finished."));
}
};
UCLASS()
class MYPROJECT_API AMyProjectGameModeBase : public AGameModeBase
{
GENERATED_BODY()
public:
virtual void BeginPlay();
MyRunnableObject* myRunnableObj;
FTimerHandle timerHandle;
FRunnableThread* myThread;
UFUNCTION()
void OnTimer();
};
void AMyProjectGameModeBase::BeginPlay()
{
Super::BeginPlay();
myRunnableObj = new MyRunnableObject();
myThread = FRunnableThread::Create(myRunnableObj, TEXT("myRunnableObj"));
GetWorldTimerManager().SetTimer(timerHandle, this, &AMyProjectGameModeBase::OnTimer, 5.0f);
}
void AMyProjectGameModeBase::OnTimer()
{
if (myThread)
{
myThread->Kill(true);
delete myRunnableObj;
delete myThread;
}
}
LogTemp: Display: Init.
LogTemp: Display: Run 0.
LogTemp: Display: Run 1.
LogTemp: Display: Run 2.
LogTemp: Display: Run 3.
LogTemp: Display: Run 4.
LogTemp: Display: Kill is called via FRunnableThread, stop now.
LogTemp: Display: Run 5.
LogTemp: Display: Run finished.