线程
2024年5月8日 2024年5月11日
- FRunnable
- GraphEvent
- FEvent
- AsyncTask
基本概念
并发和并行
-
并发:多个任务在同一时间段内执行
单核处理器,任务A、B、C,通过切换任务实现并发 -
并行:同一时刻有多个任务在执行
必然是多核的
同步和异步
-
同步
三个任务A,B,C,必须按顺序A->B->C执行 -
异步
四个任务A,B,C,D,执行完A之后才能执行B和C,B和C均执行完才能执行DA->B,C->D
使用FRunnable实现线程任务
FRunnable
Engine/Source/Runtime/Core/Public/HAL/Runnable.h
1class CORE_API FRunnable 2{ 3public: 4 virtual bool Init() 5 { 6 return true; 7 } 8 virtual uint32 Run() = 0; 9 virtual void Stop() { } 10 virtual void Exit() { } 11 virtual class FSingleThreadRunnable* GetSingleThreadInterface( ) 12 { 13 return nullptr; 14 } 15 virtual ~FRunnable() { } 16};
FFirstRunnable
FRunnable的派生类
FirstRunnable.h
1#pragma once 2 3#include "HAL/Runnable.h" 4 5class FIRSTPLUGIN_API FFirstRunnable : public FRunnable 6{ 7public: 8 FFirstRunnable() {} 9 ~FFirstRunnable() {} 10 11 virtual bool Init(); 12 virtual uint32 Run(); 13 virtual void Stop(); 14 virtual void Exit(); 15};
FirstRunnable.cpp
1#include "FirstRunnable.h" 2 3bool FFirstRunnable::Init() 4{ 5 UE_LOG(LogTemp, Display, TEXT("[%s][%d]Init FirstRunnable"), *FString(__FUNCTION__), __LINE__); 6 return true; 7} 8 9uint32 FFirstRunnable::Run() 10{ 11 UE_LOG(LogTemp, Display, TEXT("[%s][%d]Put work here"), *FString(__FUNCTION__), __LINE__); 12 return 0; 13} 14 15void FFirstRunnable::Stop() 16{ 17 UE_LOG(LogTemp, Display, TEXT("[%s][%d]Called only when received signal"), *FString(__FUNCTION__), __LINE__); 18} 19 20void FFirstRunnable::Exit() 21{ 22 UE_LOG(LogTemp, Display, TEXT("[%s][%d]After run finished"), *FString(__FUNCTION__), __LINE__); 23}
创建线程
1#include "HAL/RunnableThread.h"
1auto Runnable = new FFirstRunnable(); 2FRunnableThread *Thread = FRunnableThread::Create(Runnable, TEXT("FirstRunnable"));
日志
使用图表事件
1#include "Async/TaskGraphInterfaces.h"
A,B,C执行不论先后
1UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread start"), *FString(__FUNCTION__), __LINE__); 2 3FGraphEventRef ATask = FFunctionGraphTask::CreateAndDispatchWhenReady( 4 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]A"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 5 ENamedThreads::AnyThread); 6 7FGraphEventRef BTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 8 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]B"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 9 ENamedThreads::AnyThread); 10 11FGraphEventRef CTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 12 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]C"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 13 ENamedThreads::AnyThread); 14 15UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread end"), *FString(__FUNCTION__), __LINE__);
A->B,C->D
1UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread start"), *FString(__FUNCTION__), __LINE__); 2 3FGraphEventRef ATask = FFunctionGraphTask::CreateAndDispatchWhenReady( 4 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]A"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 5 ENamedThreads::AnyThread); 6 7FGraphEventRef BTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 8 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]B"), *FString(__FUNCTION__), __LINE__); }, TStatId(), ATask, 9 ENamedThreads::AnyThread); 10 11FGraphEventRef CTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 12 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]C"), *FString(__FUNCTION__), __LINE__); }, TStatId(), ATask, 13 ENamedThreads::AnyThread); 14 15FGraphEventArray TaskDependencies; 16TaskDependencies.Add(BTask); 17TaskDependencies.Add(CTask); 18 19FGraphEventRef DTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 20 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]D"), *FString(__FUNCTION__), __LINE__); }, TStatId(), &TaskDependencies, 21 ENamedThreads::AnyThread); 22 23UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread end"), *FString(__FUNCTION__), __LINE__);
等待执行结束
1UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread start"), *FString(__FUNCTION__), __LINE__); 2 3FGraphEventRef ATask = FFunctionGraphTask::CreateAndDispatchWhenReady( 4 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]A"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 5 ENamedThreads::AnyThread); 6 7FGraphEventRef BTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 8 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]B"), *FString(__FUNCTION__), __LINE__); }, TStatId(), ATask, 9 ENamedThreads::AnyThread); 10 11FTaskGraphInterface::Get().WaitUntilTaskCompletes(BTask); 12 13UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread end"), *FString(__FUNCTION__), __LINE__);
其他
- 使用ENamedThreads::AnyThread和ENamedThreads::GameThread决定在主线程还是子线程中执行
- 注意lambda捕获变量的生命周期
使用FEvent实现同步
1FEvent *SyncEvent = FPlatformProcess::GetSynchEventFromPool(); 2UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread start"), *FString(__FUNCTION__), __LINE__); 3 4FGraphEventRef ATask = FFunctionGraphTask::CreateAndDispatchWhenReady( 5 []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]A"), *FString(__FUNCTION__), __LINE__); }, TStatId(), nullptr, 6 ENamedThreads::AnyThread); 7 8FGraphEventRef BTask = FFunctionGraphTask::CreateAndDispatchWhenReady( 9 [&]() 10 { 11 UE_LOG(LogTemp, Display, TEXT("[%s][%d]B"), *FString(__FUNCTION__), __LINE__); 12 SyncEvent->Trigger(); 13 }, 14 TStatId(), ATask, ENamedThreads::AnyThread); 15 16SyncEvent->Wait(); 17FPlatformProcess::ReturnSynchEventToPool(SyncEvent); 18 19UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread end"), *FString(__FUNCTION__), __LINE__);
使用AsyncTask
1UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread start"), *FString(__FUNCTION__), __LINE__); 2 3AsyncTask(ENamedThreads::AnyThread, []() { UE_LOG(LogTemp, Display, TEXT("[%s][%d]ASyncTask"), *FString(__FUNCTION__), __LINE__); }); 4 5UE_LOG(LogTemp, Display, TEXT("[%s][%d]In main thread end"), *FString(__FUNCTION__), __LINE__);