六一的部落格


关关难过关关过,前路漫漫亦灿灿。



  • FRunnable
  • GraphEvent
  • FEvent
  • AsyncTask

基本概念


并发和并行

  • 并发:多个任务在同一时间段内执行

    单核处理器,任务A、B、C,通过切换任务实现并发

  • 并行:同一时刻有多个任务在执行

    必然是多核的


同步和异步

  • 同步

    三个任务A,B,C,必须按顺序A->B->C执行

  • 异步

    四个任务A,B,C,D,执行完A之后才能执行B和C,B和C均执行完才能执行D

    A->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__);



参考

并发,并行,同步和异步的基本概念

FRunnable

TaskGraph

虚幻线程类

AsyncTask类


线程


  • FRunnable
  • GraphEvent
  • FEvent
  • AsyncTask

基本概念


并发和并行

  • 并发:多个任务在同一时间段内执行

    单核处理器,任务A、B、C,通过切换任务实现并发

  • 并行:同一时刻有多个任务在执行

    必然是多核的


同步和异步

  • 同步

    三个任务A,B,C,必须按顺序A->B->C执行

  • 异步

    四个任务A,B,C,D,执行完A之后才能执行B和C,B和C均执行完才能执行D

    A->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__);



参考

并发,并行,同步和异步的基本概念

FRunnable

TaskGraph

虚幻线程类

AsyncTask类