可可西

UE4多线程概述

为了提升游戏的运行帧率,减少卡顿,UE4中使用了大量的线程来提升游戏的并发程度,来释放GamePlay游戏线程的压力。

 

具体包括:

① 将渲染的应用程序阶段的工作放在RenderThread中

② 将渲染命令提交放在RHIThread中

③ 将Actor及ActorComponent的Tick、物理模拟、动画、GC Mark等放到TaskGraph中并行化

④ GC Sweep的内存释放逻辑放在FAsyncPurge线程中

⑤ 资源放到AsyncLoading线程中异步加载

⑥ 声音放在AudioThread线程中

⑦ Stat统计数据的收集放到StatThread线程中

⑧ 在FAsyncWriter线程中写log到文件

 

#include "CoreMinimal.h"

DEFINE_LOG_CATEGORY_STATIC(TestLog, Log, All);

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FMultiThreadTest, "MyTest1.PublicTest.MultiThreadTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)  // 可被Automation System识别


class FTest1Runable : public FRunnable
{
public:
    FTest1Runable(int32 index)
    {
        ThreadIndex = index;
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Contruct: ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
    }

    virtual ~FTest1Runable() override
    {
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Destruct: ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
    }

    virtual bool Init() override   // 线程创建后,执行初始化工作   【在线程上执行】
    {
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Init: ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
        return true;
    }
    virtual uint32 Run() override   // 放置线程运行的代码   【在线程上执行】
    {
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Run: 111 ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
        
        // FPlatformProcess::Sleep(xx)可让当前线程Suspend xx秒   注:其他线程不受影响
        switch (ThreadIndex)
        {
        case 0:
            FPlatformProcess::Sleep(20.0f);
        default:
            FPlatformProcess::Sleep(1.0f);
            break;
        }
        
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Run: 222 ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
        FPlatformProcess::Sleep(2.0f);
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Run: 333 ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
        return 0;
    }
    virtual void Stop() override
    {
    }

    virtual void Exit() override   // 线程退出之前,进行清理工作   【在线程上执行】
    {
        UE_LOG(TestLog, Log, TEXT("FTest1Runable Exit: ThreadIndex:%d tid:0x%x FrameIndex:%llu"), ThreadIndex, FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
    }

private:
    int32 ThreadIndex;
};


bool FMultiThreadTest::RunTest(const FString& Parameters)
{
    UE_LOG(TestLog, Log, TEXT("RunTest Begin tid:0x%x FrameIndex:%llu"), FPlatformTLS::GetCurrentThreadId(), GFrameCounter);

    // 调用FRunnableThread::Create来创建一个线程
    FRunnableThread* Test1Thread0 = FRunnableThread::Create(new FTest1Runable(0), TEXT("Test1Thread0"));  // Test1Thread0为线程名
    FRunnableThread* Test1Thread1 = FRunnableThread::Create(new FTest1Runable(1), TEXT("Test1Thread1"));
    FRunnableThread* Test1Thread2 = FRunnableThread::Create(new FTest1Runable(2), TEXT("Test1Thread2"));

    UE_LOG(TestLog, Log, TEXT("RunTest End tid:0x%x FrameIndex:%llu"), FPlatformTLS::GetCurrentThreadId(), GFrameCounter);
    return true;
}

 

Automation System(自动化测试系统)  菜单:Window -- Developer Tools -- Session Frontend

 

 

 

执行流程解释如下:

// 游戏线程 ID:0xe08     Test1Thread0 ID: 0xa67c     Test1Thread1 ID: 0x7104     Test1Thread2 ID: 0xb294

// 在第6390帧  游戏线程调用FRunnableThread::Create创造出Test1Thread0、Test1Thread1、Test1Thread2
//            各个线程被创建出来后,在自己的线程中立即调用了Init和Run方法
[2020.09.28-07.11.59:411][390]TestLog: RunTest Begin tid:0xe08 FrameIndex:6390
[2020.09.28-07.11.59:411][390]TestLog: FTest1Runable Contruct: ThreadIndex:0 tid:0xe08 FrameIndex:6390
[2020.09.28-07.11.59:412][390]TestLog: FTest1Runable Init: ThreadIndex:0 tid:0xa67c FrameIndex:6390
[2020.09.28-07.11.59:412][390]TestLog: FTest1Runable Run: 111 ThreadIndex:0 tid:0xa67c FrameIndex:6390
[2020.09.28-07.11.59:412][390]TestLog: FTest1Runable Contruct: ThreadIndex:1 tid:0xe08 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: FTest1Runable Init: ThreadIndex:1 tid:0x7104 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: FTest1Runable Run: 111 ThreadIndex:1 tid:0x7104 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: FTest1Runable Contruct: ThreadIndex:2 tid:0xe08 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: FTest1Runable Init: ThreadIndex:2 tid:0xb294 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: FTest1Runable Run: 111 ThreadIndex:2 tid:0xb294 FrameIndex:6390
[2020.09.28-07.11.59:413][390]TestLog: RunTest End tid:0xe08 FrameIndex:6390

// 在第6474帧
// 过了1s,线程Test1Thread1、Test1Thread2执行到Run 222处
[2020.09.28-07.12.00:418][475]TestLog: FTest1Runable Run: 222 ThreadIndex:1 tid:0x7104 FrameIndex:6474
[2020.09.28-07.12.00:418][475]TestLog: FTest1Runable Run: 222 ThreadIndex:2 tid:0xb294 FrameIndex:6474


// 在第6690帧
// 再过了2s,线程Test1Thread1、Test1Thread2退出Run函数,并调用Exit函数,线程的生命周期结束
[2020.09.28-07.12.02:416][691]TestLog: FTest1Runable Run: 333 ThreadIndex:2 tid:0xb294 FrameIndex:6690
[2020.09.28-07.12.02:416][691]TestLog: FTest1Runable Exit: ThreadIndex:2 tid:0xb294 FrameIndex:6690
[2020.09.28-07.12.02:416][691]TestLog: FTest1Runable Run: 333 ThreadIndex:1 tid:0x7104 FrameIndex:6690
[2020.09.28-07.12.02:416][691]TestLog: FTest1Runable Exit: ThreadIndex:1 tid:0x7104 FrameIndex:6690

// 在第8832帧
// 过了10s,线程Test1Thread0执行到Run 222处
[2020.09.28-07.12.20:419][833]TestLog: FTest1Runable Run: 222 ThreadIndex:0 tid:0xa67c FrameIndex:8832

// 在第9072帧
// 再过了2s,线程Test1Thread0退出Run函数,并调用Exit函数,线程的生命周期结束
[2020.09.28-07.12.22:419][ 73]TestLog: FTest1Runable Run: 333 ThreadIndex:0 tid:0xa67c FrameIndex:9072
[2020.09.28-07.12.22:419][ 73]TestLog: FTest1Runable Exit: ThreadIndex:0 tid:0xa67c FrameIndex:9072

 

如果想在单线程运行模式下(带上-nothreading参数),以假线程FFakeThread的方式在游戏线程上来模拟执行的话,需要从FSingleThreadRunnable派生,并实现其GetSingleThreadInterface接口中返回当前this指针

class FStatsThread
    : public FRunnable
    , private FSingleThreadRunnable
{
// ... ...
public:
    virtual FSingleThreadRunnable* GetSingleThreadInterface() override
    {
        return this;
    }
};

 

 

1. FRunnable是线程可执行实体,其Run()函数为线程函数。Run()函数执行完,线程的生命周期也将结束

2. FRunnableThread是所有线程的基类,FRunnable为其成员变量

3. FRunnableThread相当于一个“外壳”,根据平台会创建出属于那个平台的线程。而FRunnable是“核”,定义了这个线程具体要做什么

4. FThreadManager是全局的线程管理单例(通过静态函数FThreadManager::Get()得到单例),可获取到当前运行的所有线程

5. FRunnableThreadWin用于windows平台,FRunnableThreadPThread(对pthread的封装)用于Android、iOS、Mac、Linux等平台

6. FFakeThread用于单线程运行模式下(带上-onethread参数),以假线程的方式在游戏线程上来模拟执行

7. FRunnableThread相关函数

   const uint32 GetThreadID() const; // 线程ID,唯一

   const FString & GetThreadName() const; // 线程名称 可重复

   EThreadPriority GetThreadPriority();  // 获取线程的优先级

   void SetThreadPriority( EThreadPriority NewPriority );  // 设置线程的优先级

   void Suspend( bool bShouldPause = true );   // bShouldPause为true时,pause线程;bShouldPause为false时,resume线程   注:FRunnableThreadPThread该函数为空实现

   void WaitForCompletion();  // 阻塞并等待当前线程执行完毕

   bool Kill( bool bShouldWait = true );   // 会先执行 runnable 对象的Stop函数,然后根据 bShouldWait 参数决定是否等待线程执行完毕。如果不等待,则强制杀死线程,可能会造成内存泄漏

 

线程 平台 解释

主线程

 All

相关的代码在:UnrealEngine\Engine\Source\Runtime\Launch目录中

 

windows:为游戏线程

线程函数为:LaunchWindows.cpp下的WinMain函数

mac:为游戏线程

线程函数为:INT32_MAIN_INT32_ARGC_TCHAR_ARGV,其实展开就是main

内部会调用到obj c的NSApp(系统提供的App对象)

具体应用能实现的就只有后面的Delegate,所以UE4实现了UE4AppDelegate

真正做初始化在applicationDidFinishLaunching函数中,然后调用runGameThread函数

Android:线程名为MainThread-UE4

使用java代码来处理主消息循环

Splash Activity:Engine\Build\Android\Java\src\com\epicgames\ue4\SplashActivity.java

游戏Activity:Engine\Build\Android\Java\src\com\epicgames\ue4\GameActivity.java.template

iOS:线程名为Thread <n>  如:Thead 1

线程函数为LaunchIOS.cpp下的main函数,会调用到obj c的UIApplicationMain

具体实现在IOSAppDelegate.cpp的MainAppThread函数中

 

对于Android和iOS,GameThread并不是主线程。在接入第三方SDK,一般都会从app的主线程调用回调

这时如果直接调用UE4相关函数,很有可能发生不可预知的问题,可通过AsyncTask将这些操作放在GameThread中跑

AsyncTask(ENamedThreads::GameThread, [=]()
{
SpawnActor();
//一些操作 });

游戏线程(消耗高)

 All

Windows:线程名为Main Thread

线程函数为:LaunchWindows.cpp下的WinMain函数

Android:线程名为Thread-<n>  如:Thread-3

线程函数为LaunchAndroid.cpp下的android_main函数

iOS:线程名为Thread <n>  如:Thread 5

线程函数为IOSAppDelegate.cpp下的MainAppThread函数

 

线程id:uint32 GGameThreadId

会被加入到TaskGraph系统中:FTaskGraphInterface::Get().AttachToThread(ENamedThreads::GameThread)

 

bool IsInGameThread();

渲染线程(消耗高)

 

class FRenderingThread : public FRunnable

线程函数:RenderingThreadMain

 All

线程名:RenderThread 1

 

-norenderthread参数可在启动时强制不开启RenderThread

注:开启-norenderthread参数时,最好是带上-NoLoadingScreen来禁掉loadingscreen,要不然会出现崩溃

 

可用ToggleRenderingThread控制台命令来创建和销毁RenderThread

销毁RenderThread时,渲染相关的逻辑会放回到游戏线程中

 

渲染线程的创建逻辑在void StartRenderingThread()函数中

销毁逻辑在void StopRenderingThread()函数中

 

线程id:uint32 GRenderThreadId

FRunnableThread* GRenderingThread;

会被加入到TaskGraph系统中:FTaskGraphInterface::Get().AttachToThread(RenderThread)

 

bool GUseThreadedRendering; // 是否使用独立Render线程来渲染

bool GIsThreadedRendering;  // 渲染是否在独立的Render线程中运行

TAtomic<int32> GIsRenderingThreadSuspended;  // 渲染线程是否暂停

TAtomic<int32> GSuspendRenderingTickables;  // rendering tickables是否应该更新   flush时应暂停更新

 

bool IsInActualRenderingThread();  // 渲染线程存在,且当前线程为渲染线程

bool IsInRenderingThread();  // 无渲染线程||渲染线程暂停||当前线程为渲染线程

bool IsInParallelRenderingThread(); // 与IsInRenderingThread()函数等价

RHI线程

 

class FRHIThread : public FRunnable

 All

使用独立的渲染线程时,会根据情况来决定是否创建该线程

当渲染线程销毁时,该线程也会销毁,RHI执行的逻辑会放回游戏线程中

 

-rhithread参数时(缺省),由各个平台来决定启动时是否开启RHI线程

对应bool GRHISupportsRHIThread变量,具体情况如下:

DX11缺省不开启,可以通过#define EXPERIMENTAL_D3D11_RHITHREAD 1来缺省开启

DX12在非Editor模式下默认开启

OpenGL根据FeatureLevel和r.OpenGL.AllowRHIThread的值来决定是否缺省开启
r.OpenGL.AllowRHIThread 0 // 不使用RHI线程
r.OpenGL.AllowRHIThread 1 // 使用RHI线程(缺省)

Vulklan缺省开启1个RHI线程
r.Vulkan.RHIThread 0 // 不使用RHI线程
r.Vulkan.RHIThread 1 // 使用1个RHI线程(缺省)
r.Vulkan.RHIThread 2 // 使用多个RHI线程

Metal会根据显卡芯片版本和r.Metal.IOSRHIThread的值来决定是否缺省开启
r.Metal.IOSRHIThread 0 // 不使用RHI线程(缺省)
r.Metal.IOSRHIThread 1 // 使用1个RHI线程

 

IOS缺省是没有开该线程的

 

-norhithread参数会在启动时强制不开启rhi线程

如果不开启rhi线程,rhi的逻辑会跑在RenderingThread线程中

在pc环境的运行时,可用r.RHIThread.Enable 0控制台命令切到这种方式来跑   注:RHI线程还在,只是不再往里面派发任务了

 

线程id:uint32 GRHIThreadId

FRunnableThread* GRHIThread_InternalUseOnly

会被加入到TaskGraph系统中:FTaskGraphInterface::Get().AttachToThread(ENamedThreads::RHIThread)

 

// 创建独立的RHIThread,放加入到TaskGraph中,RHI会跑在TaskGraph的RHIThread上

// 在pc环境的运行时,可用r.RHIThread.Enable 1控制台命令切到这种方式来跑

bool GUseRHIThread_InternalUseOnly;  

// 在pc环境的运行时,可用r.RHIThread.Enable 2控制台命令切到这种方式来跑

bool GUseRHITaskThreads_InternalUseOnly;  // TaskGraph中使用Any Thread来跑

 

// GUseRHIThread_InternalUseOnly为true,且正在运行时,该值为true

bool GIsRunningRHIInDedicatedThread_InternalUseOnly;  --》bool IsRunningRHIInDedicatedThread()

// GUseRHITaskThreads_InternalUseOnly为true,且正在运行时,该值为true

bool GIsRunningRHIInTaskThread_InternalUseOnly; --》bool IsRunningRHIInTaskThread()

 

// GUseRHIThread_InternalUseOnly或GUseRHITaskThreads_InternalUseOnly为true,且正在运行时,该值为true

bool GIsRunningRHIInSeparateThread_InternalUseOnly; --》bool IsRunningRHIInSeparateThread()

 

bool IsInRHIThread();

bool IsRHIThreadRunning();  // 存在RHI线程

RenderingThread的Tick驱动线程

 

class FRenderingThreadTickHeartbeat : public FRunnable

All

线程名:RTHeartBeat 1

 

负责执行rendering thread tickables

 

使用独立的渲染线程时,才会创建该线程,来执行void TickRenderingTickables()

当渲染线程销毁时,该线程也会销毁,TickRenderingTickables会放回游戏线程中来执行

 

TAtomic<bool> GRunRenderingThreadHeartbeat  // 是否使用RenderingThread心跳监视线程

                                                                       // 当使用独立线程来渲染时,会被设置成true;独立渲染线程停止时,会被设置成false

float GRenderingThreadMaxIdleTickFrequency = 40.f;  // tick频率  值越大tick次数越多,性能越差

线程池线程

 

class FQueuedThread : public FRunnable

All

线程名:PoolThread 0  ...  PoolThread <n>

 

// Global thread pool for shared async operations
extern CORE_API FQueuedThreadPool* GThreadPool;
extern CORE_API FQueuedThreadPool* GIOThreadPool;
extern CORE_API FQueuedThreadPool* GBackgroundPriorityThreadPool;

#if WITH_EDITOR
extern CORE_API FQueuedThreadPool* GLargeThreadPool;
#endif

TaskGraph线程(消耗高)

 

class FTaskThreadAnyThread : public FTaskThreadBase

注:class FTaskThreadBase : public FRunnable, FSingleThreadRunnable

 All

线程名:TaskGraphThreadHP 0  ...  TaskGraphThreadHP <n>

           TaskGraphThreadNP 0  ...  TaskGraphThreadNP <n>

           TaskGraphThreadBP 0  ...  TaskGraphThreadBP <n>

进程优先级:HP > NP > BP

 

TaskGraph只在最开始构造函数中创建所有的线程,调用栈如下:

UE4Editor-Core-Win64-Debug.dll!FTaskGraphImplementation::FTaskGraphImplementation(int __formal) Line 1158
UE4Editor-Core-Win64-Debug.dll!FTaskGraphInterface::Startup(int NumThreads) Line 1692
UE4Editor-Win64-Debug.exe!FEngineLoop::PreInitPreStartupScreen(const wchar_t * CmdLine) Line 2052
UE4Editor-Win64-Debug.exe!FEngineLoop::PreInit(const wchar_t * CmdLine) Line 3606
UE4Editor-Win64-Debug.exe!EnginePreInit(const wchar_t * CmdLine)
UE4Editor-Win64-Debug.exe!GuardedMain(const wchar_t * CmdLine)
UE4Editor-Win64-Debug.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow) Line 257

AudioThread线程(消耗较高)

 

class FAudioThread : public FRunnable

线程函数:AudioThreadMain

 All

线程名:AudioThread

 

会被加入到TaskGraph系统中:FTaskGraphInterface::Get().AttachToThread(ENamedThreads::AudioThread)

 

bool IsInAudioThread();

AudioMixerRenderThread线程(消耗高)

class IAudioMixerPlatformInterface : public FRunnable, public FSingleThreadRunnable, public IAudioMixerDeviceChangedLister

 All 线程名:AudioMixerRenderThread

class FAsyncLoadingThread final : public FRunnable, public IAsyncPackageLoader

 All

在EDL(EventDrivenLoader)模式下,是不开启该独立线程的,在主线程中Loading

bool GEventDrivenLoaderEnabled为ture时为EDL模式

 

编辑器、standalone非cook版本为EDL模式,没有该线程

Android、IOS等cook版本为Async模式,会开启该线程

 

bool IsInAsyncLoadingThread(); --》bool IsInAsyncLoadingThreadCoreUObjectInternal()

bool IsAsyncLoading(); --》bool IsAsyncLoadingCoreUObjectInternal()

void SuspendAsyncLoading(); --》void SuspendAsyncLoadingInternal()

void ResumeAsyncLoading(); --》void ResumeAsyncLoadingInternal()

bool IsAsyncLoadingSuspended(); --》bool IsAsyncLoadingSuspendedInternal()

bool IsAsyncLoadingMultithreaded(); --》bool IsAsyncLoadingMultithreadedCoreUObjectInternal()

class FAsyncLoadingThread2 final : public FRunnable, public IAsyncPackageLoader   暂时没用
class FAsyncLoadingThreadWorker : private FRunnable   暂时没用

防屏保线程

class FScreenSaverInhibitor : public FRunnable

桌面平台

宏PLATFORM_DESKTOP为1

Windows、Linux、Mac

线程名:ScreenSaverInhibitor

StatsThread线程(消耗高)

class FStatsThread : public FRunnable, FSingleThreadRunnable

 All

线程名:StatsThread

 

会被加入到TaskGraph系统中:FTaskGraphInterface::Get().AttachToThread(ENamedThreads::StatsThread)

FMediaTicker线程

class FMediaTicker : public FRunnable , public IMediaTicker

 All 线程名:FMediaTicker

class FAsyncPurge : public FRunnable

 All

extern int32 GMultithreadedDestructionEnabled;

 

[/Script/Engine.GarbageCollectionSettings]

gc.MultithreadedDestructionEnabled=True // 通过这个控制台命令来开启

 

多线程GC清理

 


class FSlateLoadingThreadTask : public FRunnable

 All

线程名:SlateLoadingThread1

 

LoadingScreen播放视频或Slate UI

 

bool IsInSlateThread();

 

/** UnrealEngine\Engine\Source\Runtime\SlateCore\Private\Rendering\SlateRenderer.cpp **/

bool IsThreadSafeForSlateRendering()
{
    return ( ( GSlateLoadingThreadId != 0 ) || IsInGameThread() );
}

bool DoesThreadOwnSlateRendering()
{
    if ( IsInGameThread() )
    {
        return GSlateLoadingThreadId == 0;
    }
    else
    {
        return FPlatformTLS::GetCurrentThreadId() == GSlateLoadingThreadId;
    }

    return false;
}

class  FPreLoadScreenSlateThreadTask : public FRunnable  All

线程名:SlateLoadingThread1

 

引擎初始化播放视频

 

bool IsInSlateThread();

template<typename ResultType>
class TAsyncRunnable : public FRunnable

 All TAsync 0
class FAsyncWriter : public FRunnable, public FArchive  All

FAsyncWriter_UAGame

 

见:OutputDeviceFile.cpp的FAsyncWriter::Run()

异步写log到文件

class FOnlineAsyncTaskManager : public FRunnable, FSingleThreadRunnable  All OnlineAsyncTaskThreadNull DefaultInstance(1)
class FLwsWebSocketsManager: public IWebSocketsManager, public FRunnable, public FSingleThreadRunnable  All LibwebsocketsThread
class FHttpThread : FRunnable, FSingleThreadRunnable  All HttpManagerThread
class FMessageRouter : public FRunnable, private FSingleThreadRunnable  All FMessageBus.DefaultBus.Router
class FLiveLinkMessageBusDiscoveryManager : FRunnable  All LiveLinkMessageBusDiscoveryManager
class FFileTransferRunnable : public FRunnable  All FFileTransferRunnable
class TcpConsoleListener : FRunnable iOS  
class FTcpListener : public FRunnable iOS  

@implementation FIOSFramePacer

-(void)run:(id)param

iOS  
windows平台Splash线程 windows 线程函数:StartSplashScreenThread
TraceLog windows

windows:线程名为TraceLog;WindowsTrace.cpp下ThreadCreate函数

Android:线程名为bundle id;AndroidTrace.cpp下ThreadCreate函数

IOS:线程名为Thread <n>;AppleTrace.cpp下ThreadCreate函数

windows平台崩溃监视线程 windows 线程函数:CrashReportingThreadProc

Shader编译线程

class FShaderCompileThreadRunnableBase : public FRunnable

编辑器

线程名:ShaderCompilingThread

拉起ShaderCompileWorker.exe进程进行shader编译

DistanceField构建线程

class FBuildDistanceFieldThreadRunnable : public FRunnable

编辑器  

class FAssetDataDiscovery : public FRunnable

编辑器

用于发现文件

线程名:FAssetDataDiscovery

 

class FAssetDataGatherer : public FRunnable

编辑器

从FAssetRegistry文件列表中搜集Asset数据

线程名:FAssetDataGatherer

class FVirtualTextureDCCCacheCleanup final : public FRunnable

编辑器 线程名:FVirtualTextureDCCCacheCleanup
class FDDCCleanup : public FRunnable 编辑器 线程名:FDDCCleanup

Wwise编辑器连接线程

class FAkWaapiClientConnectionHandler : public FRunnable

编辑器或windows、mac下的非shipping版本

线程名:WAAPIClientConnectionThread1

 

在Android局内时抓的一个ue4stats文件中,里面统计的线程如下:

 

参考

【UE4源代码观察】观察UE4的线程使用

 

posted on 2021-05-27 11:31  可可西  阅读(5194)  评论(2编辑  收藏  举报

导航