# 多线程
# 多线程基础
# 应用场景
- 向服务器发送请求,或热加载。
- 加载关卡。
# 基本操作
下面创建一个线程并进行切换:
创建一个接口TaskInterface:
//=========================TaskInterface.h============================== // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "UObject/Interface.h" #include "TaskInterface.generated.h" // This class does not need to be modified. UINTERFACE(MinimalAPI) class UTaskInterface : public UInterface { GENERATED_BODY() }; /** * */ class PYTHONTEST_API ITaskInterface { GENERATED_BODY() // Add interface functions to this class. This is the class that will be inherited to implement this interface. public: virtual void DoWork(){}; };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27创建一个线程类ThreadTask:
//===============================ThreadTask.h==================================== #pragma once #include "CoreMinimal.h" #include "TaskInterface.h" /** * */ DECLARE_DELEGATE(FThreadTask) class PYTHONTEST_API ThreadTask:public FRunnable { public: ThreadTask(); ~ThreadTask(); FThreadTask ThreadTaskDelegate; virtual uint32 Run() override; void CreateThread(ITaskInterface* TaskInterfaceTemp); private: ITaskInterface* TaskInterface; FRunnableThread *TaskTread; }; //===============================ThreadTask.cpp==================================== #include "ThreadTask.h" ThreadTask::ThreadTask() { TaskInterface = nullptr; } ThreadTask::~ThreadTask() { } uint32 ThreadTask::Run() { UE_LOG(LogTemp,Warning,TEXT("run thread!")); if(TaskInterface) { TaskInterface->DoWork(); //切换线程 FGraphEventRef MyTask = FFunctionGraphTask::CreateAndDispatchWhenReady([&]() { ThreadTaskDelegate.ExecuteIfBound(); },TStatId(),NULL,ENamedThreads::GameThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(MyTask); } return 0; } void ThreadTask::CreateThread(ITaskInterface* TaskInterfaceTemp) { this->TaskInterface=TaskInterfaceTemp; TaskTread = FRunnableThread::Create(this,TEXT("TestThread"),0,TPri_Normal); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60下面来测试一下它们:
//===========================RunThreadTaskEnv.h============================== ITaskInterface * interface; ThreadTask* NewTask; void PrintF(); //===========================RunThreadTaskEnv.cpp============================== //执行主线程内容 void ARunThreadTaskEnv::PrintF() { UE_LOG(LogTemp,Warning,TEXT("printf function! run in the main thread")); } // Called when the game starts or when spawned void ARunThreadTaskEnv::BeginPlay() { Super::BeginPlay(); interface = new ITaskInterface(); NewTask = new ThreadTask(); NewTask->ThreadTaskDelegate.BindUObject(this,&ARunThreadTaskEnv::PrintF); NewTask->CreateThread(interface); } void ARunThreadTaskEnv::EndPlay(const EEndPlayReason::Type EndPlayReason) { delete NewTask; interface = nullptr; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# GraphTask
按照顺序执行多个线程:
创建TaskGraph.h文件:
class FTaskGraph { public: FTaskGraph(float _f) :m_f(_f) { } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } FORCEINLINE TStatId GetStatId() { RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph, STATGROUP_TaskGraphTasks); } void DoTask(ENamedThreads::Type CurrentThread, FGraphEventRef Subsequents) { UE_LOG(LogTemp, Warning, TEXT("Hello World %f"), m_f); } static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; } protected: private: float m_f; };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34按先后顺序创建多线程:
//延时构造 TGraphTask<FTaskGraph>::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(4.5f);
1
2
# AsyncTask
创建异步线程:
创建TaskAsyncTask.h文件:
class TaskAsyncTask : public FNonAbandonableTask { friend class FAsyncTask<TaskAsyncTask>; int32 InstanceInt; TaskAsyncTask( int32 _InstanceInt) :InstanceInt(_InstanceInt) { } void DoWork() { UE_LOG(LogTemp, Warning, TEXT("DoWork %d"), InstanceInt); } FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(TaskAsyncTask, STATGROUP_ThreadPoolAsyncTasks); } }; void m_Main() { //可使用一个现有的类 AsyncTask(ENamedThreads::GameThread, [&]() { UE_LOG(LogTemp, Warning, TEXT("DoWork")); }); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30使用上面类创建异步线程:
void ARunThreadTaskEnv::BeginPlay() { FAsyncTask<TaskAsyncTask> *MyTask = new FAsyncTask<TaskAsyncTask>(3); MyTask->StartBackgroundTask(); //MyTask->StartSynchronousTask();//执行线程为游戏线程,同步执行。 if(MyTask->IsDone()) { UE_LOG(LogTemp, Warning, TEXT("MyTask->IsDone() is finished!")); } MyTask->EnsureCompletion(); delete MyTask; }
1
2
3
4
5
6
7
8
9
10
11
12
# 总结
- Runnable:用于复杂计算。
- GraphTask:可规定多线程任务的执行顺序。
- AsyncTask:从线程池中调用,使用空闲线程。
注意下面操作只能在主线程中使用:
- SpawnActor
- NewObject
- Destroy UObject/Actor
- DrawDebugLine