FRunnable可以在主线程之外的线程中执行代码,当需要并行做某些事的时候会有用。
虽然在之前的《UE4使用FScopeLock做线程锁》中已顺便创建一个简单的FRunnable的代码,但是不够简单。我想再整理下,得到一个最简单的代码,方便之后用到时直接复制这里。
整理出“建立一个最简单的FRunnable所需的代码”。
首先,需要继承FRunnable创建自己的子类:
TestRunnable.h:
#pragma once
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
class FTestRunnable : public FRunnable
{
public:
// FRunnable methods.
virtual uint32 Run() override;
virtual void Stop() override;
};
想要在这个线程中执行的代码放在Run中。而当在外部终止这个Runnable时,Stop会被调用。
我这里用于测试的 TestRunnable.cpp 如下:
#include"TestRunnable.h"
#include"CoreMinimal.h"
#include"HAL/PlatformProcess.h"
DEFINE_LOG_CATEGORY_STATIC(LogYaksueTest, Log, All);
uint32 FTestRunnable::Run()
{
//在此处写想要执行的代码:
{
//作为测试,每1秒打印一次当前时间,执行10次
for (int i = 0; i < 10; i++)
{
FPlatformProcess::Sleep(1.0f);
UE_LOG(LogYaksueTest, Warning, TEXT("%s"), *FDateTime::Now().ToString());
}
}
return 0;
}
void FTestRunnable::Stop()
{
UE_LOG(LogYaksueTest, Warning, TEXT("Stop!"));
}
然后,不仅需要创建FRunnable,还需要创建一个FRunnableThread。
这里我为了方便,直接声明两个 static 指针用于存放他们:
static FRunnableThread* TestRunnableThread = nullptr;
static FTestRunnable* TestRunnable = nullptr;
启动时,new出一个Runnable,然后用FRunnableThread::Create创建出RunnableThread:
TestRunnable = new FTestRunnable();
TestRunnableThread = FRunnableThread::Create(TestRunnable, TEXT("TestRunnable"), 0, TPri_Normal);
想要终止时,调用Kill:
TestRunnableThread->Kill();
delete TestRunnableThread;
TestRunnableThread = nullptr;
启动后,Runnable就开始执行了,我这里是测试每秒打印1次log。由于不是在主线程中执行的,所以就算用了 FPlatformProcess::Sleep 编辑器也没有卡死。并且,主线程中的操作也不会影响Runnable的执行。

另外要注意的是:我其实在3秒多的时候就调用了Kill,可以看到FTestRunnable::Stop()也确实被调用了。但是Run中的代码还在继续执行(并且此时编辑器卡死)。因此,如果想要终止得更及时,应该需要围绕Stop做些逻辑(比如在Stop中将 bStopping 设置为true,而在Run中检查到 bStopping 为true就立马停止执行后续的代码)
在UE中建立一个最简单的FRunnable所需的代码为:
FRunnable子类,在Run中放想要这个线程执行的代码,在Stop中放外部终止它时应该被调用的代码。new出一个 Runnable,然后用FRunnableThread::Create创建出 RunnableThread。Kill: