moushen

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Runnable线程和切换线程

首先模拟创造线程的过程,创建一个接口类,预留一个函数

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UTaskInterface : public UInterface
{
    GENERATED_BODY()
};

/**
 * 
 */
class ADVANCEPROJECT_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(){}
    
};

 

然后就是现线程类,继承FRunnable

 

DECLARE_DELEGATE(FThreadDeclare)

class ADVANCEPROJECT_API ThreadTask : public FRunnable
{
public:
    ThreadTask();
    FThreadDeclare* MainThreadDeclare;

    virtual uint32 Run();

    void CreateThread(ITaskInterface* NewTaskInter);

    ~ThreadTask();

private:
    ITaskInterface* TaskInterface;
    FRunnableThread* Task_Thread;
};

 

 

CPP:

ThreadTask::ThreadTask() { TaskInterface
=nullptr; }
//新线程开启后,会运行重写的Run方法 uint32 ThreadTask::Run() { UE_LOG(LogTemp,Log,TEXT(
"Run")); if (TaskInterface) {
     //新线程 TaskInterface
->DoWork();      //这里插入一个线程方法,在他准备完毕后,会执行绑定的方法,会回到这个方法所规定线程,如果他绑定过的话。 FGraphEventRef taskRef = FFunctionGraphTask::CreateAndDispatchWhenReady([&]() { MainThreadDeclare->ExecuteIfBound(); },TStatId(),nullptr,ENamedThreads::GameThread); FTaskGraphInterface::Get().WaitUntilTaskCompletes(taskRef); } return 0; }
//真正意义上的开一个新线程
void ThreadTask::CreateThread(ITaskInterface* NewTaskInter) { TaskInterface = NewTaskInter; Task_Thread = FRunnableThread::Create(this,TEXT("HelloWorld"),0,TPri_Normal); } ThreadTask::~ThreadTask() { }

 

  NewInter = new ITaskInterface();
    
    NewTask = new ThreadTask();
    //绑定代理,将主线程的一个函数绑定给他的代理
    NewTask->MainThreadDeclare->BindUObject(this,&AAdvanceProjectGameModeBase::Print_V);
    //开辟线程,运行newtask的run()
    NewTask->CreateThread(NewInter);

 

 

图例:

在create线程前,绑定工作还在主线程做

 

 

 

 

到run这里,就变成自己的线程名了。

 

 

 

 

 

 

 

 

然后在切换线程部分,在执行函数准备完成之前,依旧还是在我们的线程里工作。

 

 

 

 

准备完毕,进入代理函数,回到主线程

 

 

 

 

 

GraphTask线程

这四个接口方法为固定形式

#pragma once

#include "CoreMinimal.h"

class FTaskGraph
{
private:
    float _Str;
public:
    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, Log, TEXT("HelloWorld %f"),_Str);
    }

    static ENamedThreads::Type GetDesiredThread()
    {
        return ENamedThreads::AnyThread;
    }

    FTaskGraph(float NewStr): _Str(NewStr)
    {
    }

};

 

//支持构造方法传递参数
TGraphTask<FTaskGraph>::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(7.7f);

 

 

AsyncTask线程

#pragma once

#include "CoreMinimal.h"

class FMyAsyncTask : public FNonAbandonableTask
{
    friend class FAsyncTask<FMyAsyncTask>;

    int32 InstanceInt;

public:
    FMyAsyncTask(int32 NewInt): InstanceInt(NewInt)
    {
    }

    void DoWork()
    {
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("DoWork %d"));
        UE_LOG(LogTemp,Log,TEXT("DoWork %d"),InstanceInt);
    }

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

    
};

 

 

   

   FAsyncTask<FMyAsyncTask>* MyAsync = new FAsyncTask<FMyAsyncTask>(666);
   //选择是否为顺序执行还是异步执行,这里是异步 MyAsync
->StartBackgroundTask(); if (MyAsync->IsDone()) { delete MyAsync; MyAsync = nullptr; }

 

 

三种不同点

1.Runnable,是真正意义上的开新线程,开启的过程比较消耗性能,这个线程可以用作大型复杂的计算,比如与数据库、服务器的交互

2.GraphTask线程可以确定自己的任务顺序,其中一个参数可以放前置条件,只有前置条件完成后,才会运行本身

 

3.为了避免不必要的消耗,可以使用AsyncTask线程从线程池里调用,直接使用。也不需要像GraphTask一样创建一个函数类去初始化。

 

 

 

 

 另外,只能在主线程完成的任务绝对不能放到其他线程执行。

 

 

posted on 2020-07-14 15:21  moushen  阅读(150)  评论(0)    收藏  举报