一,UE 线程体系
- 进程:程序的一次运行实例,是操作系统分配资源和隔离的基本单位,一个进程至少有一个线程;
- 线程:进程内部的执行单元,是 CPU 调度和执行的基本单位;
- 线程是操作系统调度的独立执行流,线程属于进程,共享进程的地址空间和大部分资源;
- 并发:同一时间段内处理多个任务,任务交替推进(逻辑上同时处理);
- 并行:同一时刻同时执行多个任务,真正同时运行(物理上同时执行);
cpp
// UE 主要线程类型(分别负责不同任务,运行在 CPU 上)
UE 线程体系
├── 主线程 GameThread (游戏逻辑主线程,Tick、Actor、UObject、蓝图等)
│ └── 本质:引擎启动时的主线程,非FRunnableThread::Create创建;
│
├── 专用线程(Dedicated Threads)
│ ├── RenderThread (渲染逻辑,负责将场景数据转换为渲染命令)
│ │ └── FRenderingThread : FRunnable → FRunnableThread::Create
│ ├── RHIThread (负责将渲染命令提交给GPU,可禁用或与Render Thread合并;)
│ │ └── FRHIThread : FRunnable → FRunnableThread::Create
│ ├── AudioThread (音频混音与播放)
│ │ └── AudioRenderThread → FRunnableThread
│ ├── LoadingThread (异步加载资源)
│ │ └── FAsyncLoadingThread : FRunnable → FRunnableThread
│ ├── StatsThread (性能统计)
│ │ └── FStatsThread : FRunnable → FRunnableThread
│ └── FileI/OThread (文件读写)
│ └── 通常由平台异步 I/O 或线程池处理,不一定有专用 FRunnableThread;
│
└── 线程池线程(Thread Pool / TaskGraph)
├── WorkerThreads (由 TaskGraph / FScheduler 统一管理)
│ ├── 底层:通过 FRunnableThread 或平台线程封装创建系统线程
│ ├── 类型:PoolThread、TaskGraphThread 等
│ └── 用途:AsyncTask、ParallelFor、TaskGraph 短任务
│
└── 其他线程池 (逻辑线程池,复用 TaskGraph 工作线程)
├── GIOThreadPool
├── GBackgroundPriorityThreadPool
└── GLargeThreadPool
cpp
// GPU 运行Shader和计算任务
顶点着色器
像素着色器
计算着色器
几何着色器
细分着色器
光线追踪着色器
GPU 粒子、Niagara GPU 模拟
Lumen、Nanite、虚拟纹理等 GPU 管线
cpp
// 渲染一帧流程
// Game Thread 更新游戏逻辑
// Render Thread 收集场景数据,做可见性裁剪,生成渲染命令
// RHI Thread 把命令翻译成图形 API 调用,提交到 GPU 命令队列
// GPU 异步执行这些命令,跑各种 Shader,渲染出画面
// GPU 渲染完成后,通知 CPU,交换缓冲区,显示下一帧
UE 渲染一帧
├── CPU:准备与提交 (异步流水线)
│ ├── GameThread (游戏线程)
│ │ ├── Tick 游戏逻辑 (Actor/Component Tick,动画更新,物理模拟,蓝图/脚本)
│ │ ├── 更新场景数据 (变换矩阵,材质参数,骨骼矩阵)
│ │ └── ENQUEUE_RENDER_COMMAND (把渲染任务推给 Render Thread)
│ ├── RenderThread (渲染线程)
│ │ ├── 可见性裁剪 (视锥裁剪,遮挡剔除,距离裁剪)
│ │ ├── 图元处理 (Primitive → FMeshBatch)
│ │ ├── 生成 FMeshDrawCommand (按 Pass 分组,绑定 PSO,绑定资源)
│ │ └── 生成 RHI 命令列表
│ └── RHIThread (RHI 线程)
│ ├── 翻译成图形 API 调用 (D3D12,Vulkan,Metal)
│ ├── 录制命令缓冲区
│ └── 提交到 GPU 命令队列
│
├── GPU 命令队列 (按提交顺序排队)
│
├── GPU:渲染管线执行 (RDG 调度)
│ ├── PrePass (深度预计算)
│ │ ├── 顶点着色器绘制几何体
│ │ ├── 计算场景深度
│ │ └── Nanite 路径 (生成 NaniteVisBuffer)
│ ├── LumenSceneUpdate (Lumen 场景更新)
│ │ ├── 收集场景数据
│ │ ├── 更新距离场
│ │ ├── 更新体素结构
│ │ └── 更新表面缓存
│ ├── BasePass (基础 Pass)
│ │ ├── 像素着色器执行
│ │ └── 写入 GBuffer (漫反射,法线,粗糙度,金属度)
│ ├── 光照与阴影
│ │ ├── DiffuseIndirectAndAO (间接光照,环境光遮蔽)
│ │ ├── ShadowDepth (阴影贴图,VSM 虚拟阴影贴图)
│ │ └── Lights (直接光照, 标准延迟光照)
│ ├── 大气与水体
│ │ ├── SingleLayerWater (单层水)
│ │ ├── SkyAtmosphere (天空大气)
│ │ ├── Exponential Height Fog (高度雾)
│ │ └── Volumetric Cloud (体积云)
│ ├── Translucency (半透明)
│ │ ├── 透明材质渲染
│ │ ├── 与扭曲交互
│ │ ├── 与景深交互
│ │ └── 与不透明场景混合
│ └── PostProcessing (后处理)
│ ├── 动态曝光
│ ├── 运动模糊
│ ├── 景深
│ ├── 色调映射
│ └── TSR (超分辨率)
│
├── 最终输出
│ ├── 保存到 BackBuffer (后备缓冲区)
│ ├── UI 绘制
│ ├── 显示引擎 Present
│ └── 显示器显示
│
└── 跨帧流水线 (异步重叠)
├── Game Thread:第 N+1 帧
├── Render Thread:第 N 帧
├── RHI Thread:第 N 帧
└── GPU:第 N-1 帧
|-------------------------------------|----------------------------------|----------------------------------|
| FRunnable + FRunnableThread | 专用线程,需要完全控制线程生命周期; | 适用于长期运行的后台任务,如渲染、异步加载、网络监听等; |
| AsyncTask | 将任务丢到线程池中异步执行,无需管理线程; | 适用于短小、独立的异步操作,无需创建专用类或线程 |
| TaskGraph | UE 核心任务调度系统,管理着线程池; | 适用于构建复杂的、有依赖关系的任务流,是许多引擎子系统的基础; |
| ParallelFor | 将一个大循环并行化,自动分配到线程池; | 适用于对大型数据集进行相同的独立操作,如遍历数组进行计算; |
| FAsyncTask | 基于 FRunnable 的、可排队的异步任务封装; | 适用于需要在后台执行、并可被任务队列管理(如暂停、取消)的操作; |
| FNonAbandonableTask | 定义不可放弃的任务,强调任务的完成性; | 适用于需要确保一旦开始就必须执行完毕的关键后台工作; |
[UE 多线程方案]
二,FRunnableThread
cpp
// 抽象接口,定义一个任务在独立线程上运行的完整生命周期,本身非线程,只是描述线程要执行什么的对象;
// 用于实现自定义多线程任务,将耗时的逻辑放到独立线程中执行,避免阻塞游戏主线程;
class FRunnable
{
public:
virtual bool Init() { return true; }
virtual void Stop() { }
virtual void Exit() { }
virtual class FSingleThreadRunnable* GetSingleThreadInterface() { return nullptr; }
virtual ~FRunnable() { }
};
cpp
// MyWorker.h
#pragma once
#include "CoreMinimal.h"
#include "HAL/Runnable.h"
class FMyWorker : public FRunnable
{
public:
FMyWorker();
virtual ~FMyWorker();
virtual bool Init() override;
virtual uint32 Run() override;
virtual void Stop() override;
virtual void Exit() override;
private:
FThreadSafeBool bStopRequested; // 线程安全停止标志
};
cpp
// MyWorker.cpp
#include "MyWorker.h"
#include "HAL/RunnableThread.h"
#include "HAL/PlatformProcess.h"
FMyWorker::FMyWorker() : bStopRequested(false) {}
FMyWorker::~FMyWorker() {}
bool FMyWorker::Init() { return true; } // 在此进行初始化,例如分配资源
uint32 FMyWorker::Run() // 这是线程的主要执行体
{
while (!bStopRequested)
{
// 执行你的任务...
// 例如:处理数据、计算等
// 为避免过度占用 CPU,可以适当休眠
FPlatformProcess::Sleep(0.01f);
}
return 0;
}
void FMyWorker::Stop() { bStopRequested = true; }
void FMyWorker::Exit() {} // 在此进行清理,例如释放资源
cpp
// 启动
FMyWorker* Worker = new FMyWorker();
FRunnableThread* Thread = FRunnableThread::Create(Worker, TEXT("MyWorkerThread"));
// ... 在需要停止时 ...
// 请求停止
Worker->Stop();
// 等待线程结束并释放资源
if (Thread)
{
Thread->WaitForCompletion();
delete Thread;
Thread = nullptr;
}
delete Worker;
Worker = nullptr;