1. 源代码

  AsyncWork.h

2. 多线程的使用

  参考文档:https://wiki.unrealengine.com/Using_AsyncTasks

  当我们需要执行一个需要很长时间的任务时,放在主线程里会导致很卡,把此任务放到其他线程里则会好很多,此时多线程就可以起到关键的作用了。

  在UE4里,我们可以使用FAsyncTask 或者FAutoDeleteAsyncTask。

  使用FAsyncTask 时,我们需要手动停止或删除任务;使用FAutoDeleteAsyncTask时,系统则会自动在任务结束后,删除任务。

  需要先建个继承FNonAbandonableTask的类,如源码中的例子:

class ExampleAutoDeleteAsyncTask : public FNonAbandonableTask
    {
        friend class FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>;

        int32 ExampleData;

        ExampleAutoDeleteAsyncTask(int32 InExampleData)
         : ExampleData(InExampleData)
        {
        }

        void DoWork()
        {
            ... do the work here
        }

        FORCEINLINE TStatId GetStatId() const
        {
            RETURN_QUICK_DECLARE_CYCLE_STAT(ExampleAutoDeleteAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
        }
    };

   然后具体调用就是:

void Example()
    {
        // start an example job
        (new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(5)->StartBackgroundTask();

        // do an example job now, on this thread
        (new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(5)->StartSynchronousTask();
    }

  注意:StartBackgroundTask()是在另一个线程中执行此任务;StartSynchronousTask()是在当前线程中马上执行此任务。

  举个例子:

.h:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Kismet/KismetSystemLibrary.h"
#include "MyActor.generated.h"


UCLASS()
class ASYNCWORKSTUDY_API AMyActor : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor's properties
    AMyActor();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    void TestAsync(FString Content);

    //多线程例子
    void Example();

};

class ExampleAutoDeleteAsyncTask : public FNonAbandonableTask
{
    friend class FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>;

    int32 ExampleData;

    UObject* Object;

    AMyActor* Target;

    ExampleAutoDeleteAsyncTask(int32 InExampleData, UObject* InObject, AMyActor* InTarget)
        : ExampleData(InExampleData),
        Object(InObject),
        Target(InTarget)
    {
    }

    void DoWork()
    {
        UKismetSystemLibrary::PrintString(Object, FString::FromInt(ExampleData));

        //调用AMyactor的测试函数
        if (Target) Target->TestAsync("Success");
    }

    FORCEINLINE TStatId GetStatId() const
    {
        RETURN_QUICK_DECLARE_CYCLE_STAT(ExampleAutoDeleteAsyncTask, STATGROUP_ThreadPoolAsyncTasks);
    }
};

.cpp:
    #include "MyActor.h"


// Sets default values
AMyActor::AMyActor()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
    Super::BeginPlay();
    UKismetSystemLibrary::PrintString(this, "Hello");
    Example();
    
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    
}

void AMyActor::TestAsync(FString Content)
{
    UKismetSystemLibrary::PrintString(this, Content);
}

void AMyActor::Example()
{
    //在其他线程里执行此任务
    auto task = new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(10, GetWorld(), this);
    if (task) task->StartBackgroundTask();
    //此任务会在当前线程中马上开始。
    auto task2= new FAutoDeleteAsyncTask<ExampleAutoDeleteAsyncTask>(15, GetWorld(), this);
    if (task2) task2->StartSynchronousTask();
}