记个笔记:UE Thread&Socket

​ 最近学习UE学到了多线程和Socket的内容,将学到的东西整理一下,记个笔记!!!

​ 学习工具:

UE ^5.0.3
Rider ^2022.2.4

Thread

FRunnable

一、简单实现

​ 为了方便调试,新建C++类继承自GameInstanceSubsystem类和空类。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

​ 代码如下:

STGameInstanceSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "STGameInstanceSubsystem.generated.h"

class FThreadRunnable;
class FRunnableThread;

/**
 * 
 */
UCLASS()
class SOCKETANDTHREAD_API USTGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	//这个子系统是否应该被创建
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

	//执行这个系统实例的初始化
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	//执行这个系统实例的销毁
	virtual void Deinitialize() override;
	//对实例获取的一种封装
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	static USTGameInstanceSubsystem* Get();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StopThread();
private:
	//单例模式
	static USTGameInstanceSubsystem* GameInstanceSubsystem;
	TSharedPtr<FThreadRunnable> ThreadRunnable;
	FRunnableThread* RunnableThread;  //Runnable对象的接口,此接口是用于管理线程运行生命周期的方法
};

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	//MakeShared的参数是T构造函数参数
	ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	//FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

FThreadRunnable.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "HAL/Runnable.h"  // Runnable对象的接口,用于指定线程总体执行架构
#include "HAL/ThreadSafeBool.h"

/**
 * 
 */
class SOCKETANDTHREAD_API FThreadRunnable : public FRunnable
{
public:
	FThreadRunnable();
	FThreadRunnable(FString InThreadName);
	~FThreadRunnable();
public:
	//初始化Runnable对象
	virtual bool Init() override;

	//运行Runnable对象
	virtual uint32 Run() override;

	//停止Runnable对象
	virtual void Stop() override;

	//退出Runnable对象
	virtual void Exit() override;
private:
	FString ThreadName;
	bool IsRunning{false};
public:
	FORCEINLINE FString GetThreadName() const { return ThreadName; }
};

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
}

FThreadRunnable::~FThreadRunnable()
{
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	IsRunning = true;
	while (IsRunning)
	{
		FPlatformProcess::Sleep(3.f);
		UE_LOG(LogTemp, Warning, TEXT("Thread is running."));
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	IsRunning = false;
}

void FThreadRunnable::Exit()
{
}

​ 在关卡蓝图中写入如下代码。

在这里插入图片描述

二、线程暂停
  1. 变量方式

STGameInstanceSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "STGameInstanceSubsystem.generated.h"

class FThreadRunnable;
class FRunnableThread;

/**
 * 
 */
UCLASS()
class SOCKETANDTHREAD_API USTGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	//这个子系统是否应该被创建
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

	//执行这个系统实例的初始化
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	//执行这个系统实例的销毁
	virtual void Deinitialize() override;
	//对实例获取的一种封装
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	static USTGameInstanceSubsystem* Get();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StopThread();
    /**变量方式**/
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void SuspendThread(bool bIsSuspend);
    /**变量方式**/
private:
	//单例模式
	static USTGameInstanceSubsystem* GameInstanceSubsystem;
	TSharedPtr<FThreadRunnable> ThreadRunnable;
	FRunnableThread* RunnableThread;  //Runnable对象的接口,此接口是用于管理线程运行生命周期的方法
};

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	//MakeShared的参数是T构造函数参数
	ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	//FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}
/**变量方式**/
void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	ThreadRunnable->Suspend(bIsSuspend);
}
/**变量方式**/

FThreadRunnable.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "HAL/Runnable.h"  // Runnable对象的接口,用于指定线程总体执行架构
#include "HAL/ThreadSafeBool.h"

/**
 * 
 */
class SOCKETANDTHREAD_API FThreadRunnable : public FRunnable
{
public:
	FThreadRunnable();
	FThreadRunnable(FString InThreadName);
	~FThreadRunnable();
public:
	//初始化Runnable对象
	virtual bool Init() override;

	//运行Runnable对象
	virtual uint32 Run() override;

	//停止Runnable对象
	virtual void Stop() override;

	//退出Runnable对象
	virtual void Exit() override;
    /**变量方式**/
	void Suspend(bool bIsSuspend);
    /**变量方式**/
private:
	FString ThreadName;
	bool bIsRunning{false};
	bool bIsPause{false};
public:
	FORCEINLINE FString GetThreadName() const { return ThreadName; }
};

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
}

FThreadRunnable::~FThreadRunnable()
{
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	bIsRunning = true;
	while (bIsRunning)
	{
        /**变量方式**/
		if(bIsPause)
		{
			continue;
		}
        /**变量方式**/
		FPlatformProcess::Sleep(3.f);
		UE_LOG(LogTemp, Warning, TEXT("Thread is running."));
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	bIsRunning = false;
    bIsPause = false;
}

void FThreadRunnable::Exit()
{
}
/**变量方式**/
void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}
/**变量方式**/

​ 在关卡蓝图中写入如下代码。

在这里插入图片描述

  1. Suspend方法

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	//MakeShared的参数是T构造函数参数
	ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	//FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
    /**Suspend方法**/
	RunnableThread->Suspend(bIsSuspend);
    /**Suspend方法**/
}
  1. FEvent方法(推荐)

STGameInstanceSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "STGameInstanceSubsystem.generated.h"

class FThreadRunnable;
class FRunnableThread;

/**
 * 
 */
UCLASS()
class SOCKETANDTHREAD_API USTGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	//这个子系统是否应该被创建
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

	//执行这个系统实例的初始化
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	//执行这个系统实例的销毁
	virtual void Deinitialize() override;
	//对实例获取的一种封装
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	static USTGameInstanceSubsystem* Get();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StopThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void SuspendThread(bool bIsSuspend);
    /**FEvent方法**/
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void PauseThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void WakeupThread();
    /**FEvent方法**/
private:
	//单例模式
	static USTGameInstanceSubsystem* GameInstanceSubsystem;
	TSharedPtr<FThreadRunnable> ThreadRunnable;
	FRunnableThread* RunnableThread;  //Runnable对象的接口,此接口是用于管理线程运行生命周期的方法
};

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	//MakeShared的参数是T构造函数参数
	ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	//FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}
 /**FEvent方法**/
void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}
 /**FEvent方法**/

FThreadRunnable.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "HAL/Runnable.h"  // Runnable对象的接口,用于指定线程总体执行架构
#include "HAL/ThreadSafeBool.h"

class FEvent;
/**
 * 
 */
class SOCKETANDTHREAD_API FThreadRunnable : public FRunnable
{
public:
	FThreadRunnable();
	FThreadRunnable(FString InThreadName);
	~FThreadRunnable();
public:
	//初始化Runnable对象
	virtual bool Init() override;

	//运行Runnable对象
	virtual uint32 Run() override;

	//停止Runnable对象
	virtual void Stop() override;

	//退出Runnable对象
	virtual void Exit() override;
	void Suspend(bool bIsSuspend);
     /**FEvent方法**/
	void PauseThread();
	void WakeupThread();
     /**FEvent方法**/
private:
	FString ThreadName;
	bool bIsRunning{false};
	bool bIsPause{false};
     /**FEvent方法**/
	FEvent* ThreadEvent;
     /**FEvent方法**/
public:
	FORCEINLINE FString GetThreadName() const { return ThreadName; }
};

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
     /**FEvent方法**/
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
     /**FEvent方法**/
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
     /**FEvent方法**/
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
     /**FEvent方法**/
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	bIsRunning = true;
	while (bIsRunning)
	{
		if(bIsPause)
		{
             /**FEvent方法**/
			if(ThreadEvent)
			{
				//Wait:线程阻塞,直到线程被Triggered
				ThreadEvent->Wait();
				if(!bIsRunning)
				{
					return uint8();
				}
			}
             /**FEvent方法**/
		}
		FPlatformProcess::Sleep(3.f);
		UE_LOG(LogTemp, Warning, TEXT("Thread is running."));
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}
 /**FEvent方法**/
void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}
 /**FEvent方法**/
三、线程退出

STGameInstanceSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "STGameInstanceSubsystem.generated.h"

class FThreadRunnable;
class FRunnableThread;

/**
 * 
 */
UCLASS()
class SOCKETANDTHREAD_API USTGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	//这个子系统是否应该被创建
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

	//执行这个系统实例的初始化
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	//执行这个系统实例的销毁
	virtual void Deinitialize() override;
	//对实例获取的一种封装
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	static USTGameInstanceSubsystem* Get();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartThread();
    /**线程退出**/
	//线程退出
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StopThread();
    /**线程退出**/
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void SuspendThread(bool bIsSuspend);
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void PauseThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void WakeupThread();
    /**线程退出**/
	//强制线程退出
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void Shutdown(bool bShouldWait);
    /**线程退出**/
private:
	//单例模式
	static USTGameInstanceSubsystem* GameInstanceSubsystem;
	TSharedPtr<FThreadRunnable> ThreadRunnable;
	FRunnableThread* RunnableThread;  //Runnable对象的接口,此接口是用于管理线程运行生命周期的方法
};

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	//MakeShared的参数是T构造函数参数
	ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	//FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
}
/**线程退出**/
void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}
/**线程退出**/
void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}
/**线程退出**/
void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if(RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}
/**线程退出**/

ThreadLock

一、原子变量

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
    /**原子变量**/
	for(int32 i = 0; i < 2; i ++)
	{
		//仅用于演示,有内存泄露问题
		FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
		FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	}
     /**原子变量**/
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if(RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"


 /**原子变量**/
const int32 MAX_COUNT = 50;

TAtomic<int32> number = 0;
 /**原子变量**/

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
     /**原子变量**/
	for(int32 i = 0; i < MAX_COUNT; i ++)
	{
		number++;
		UE_LOG(LogTemp, Warning, TEXT("Thread %s, %d"), *ThreadName, number.Load());
		FPlatformProcess::Sleep(0.01f);
	}
	return uint32();
     /**原子变量**/
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}

void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}
二、自旋锁

​ 它是一种基于忙等待(busy-wait)的锁,当一个线程尝试获取锁时,如果锁已经被其他线程占用,则该线程会不断循环检查锁是否可用,直到获取到锁为止。自旋锁适用于锁的持有时间比较短的场景,因为它会占用大量的CPU时间,造成性能损失。

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

const int32 MAX_COUNT = 50;

// TAtomic<int32> number = 0;

int32 number = 0;
/**自旋锁**/
UE::FSpinLock Lock;
/**自旋锁**/

FRWLock RWLock;

FCriticalSection CriticalSection;

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	for(int32 i = 0; i < MAX_COUNT; i ++)
	{
        /**自旋锁**/
		Lock.Lock();
        /**自旋锁**/
		number++;
		UE_LOG(LogTemp, Warning, TEXT("Thread %s, %d"), *ThreadName, number);
        /**自旋锁**/
		Lock.Unlock();
        /**自旋锁**/
		FPlatformProcess::Sleep(0.01f);
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}

void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}
三、读写锁

​ 它是一种特殊的锁,用于保护读写操作的共享资源。读写锁允许多个线程同时对资源进行读操作,但只允许一个线程进行写操作。读写锁适用于读操作比写操作频繁的场景,因为它可以提高读取性能,降低写入竞争的代价。

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

const int32 MAX_COUNT = 50;

// TAtomic<int32> number = 0;

int32 number = 0;

UE::FSpinLock Lock;
 /**读写锁**/
FRWLock RWLock;
 /**读写锁**/
FCriticalSection CriticalSection;

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	for(int32 i = 0; i < MAX_COUNT; i ++)
	{
         /**读写锁**/
		RWLock.WriteLock();
		number++;
		RWLock.WriteUnlock();
		RWLock.ReadLock();
		UE_LOG(LogTemp, Warning, TEXT("Thread %s, %d"), *ThreadName, number);
		RWLock.ReadUnlock();
         /**读写锁**/
		FPlatformProcess::Sleep(0.01f);
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}

void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}
四、临界区

​ 它是一种基于操作系统内核对象的锁,采用了互斥量(mutex)来保护临界区,确保同一时间只有一个线程能访问临界区。临界区适用于需要保护共享资源的场景,因为它能够提供较高的并发性和较低的竞争代价。

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

const int32 MAX_COUNT = 50;

// TAtomic<int32> number = 0;

int32 number = 0;

UE::FSpinLock Lock;

FRWLock RWLock;
/**临界锁**/
FCriticalSection CriticalSection;
/**临界锁**/

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	for(int32 i = 0; i < MAX_COUNT; i ++)
	{
        /**临界锁**/
		CriticalSection.Lock();
		number++;
		UE_LOG(LogTemp, Warning, TEXT("Thread %s, %d"), *ThreadName, number);
		CriticalSection.Unlock();
        /**临界锁**/
		FPlatformProcess::Sleep(0.01f);
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}

void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}
五、FScopeLock(推荐)

FThreadRunnable.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FThreadRunnable.h"

const int32 MAX_COUNT = 50;

// TAtomic<int32> number = 0;

int32 number = 0;

UE::FSpinLock Lock;

FRWLock RWLock;
/**FScopeLock**/
FCriticalSection CriticalSection;
/**FScopeLock**/

FThreadRunnable::FThreadRunnable()
{
}

FThreadRunnable::FThreadRunnable(FString InThreadName): ThreadName(InThreadName)
{
	//GetSynchEventFromPool:从事件池中获取事件或创建事件
	ThreadEvent = FPlatformProcess::GetSynchEventFromPool();
}

FThreadRunnable::~FThreadRunnable()
{
	UE_LOG(LogTemp, Warning, TEXT("~FThreadRunnable"));
	//ReturnSynchEventToPool:返回事件到事件池中
	FPlatformProcess::ReturnSynchEventToPool(ThreadEvent);
	ThreadEvent = nullptr;
}

bool FThreadRunnable::Init()
{
	if (!FRunnable::Init())
	{
		return false;
	}
	return true;
}

uint32 FThreadRunnable::Run()
{
	for(int32 i = 0; i < MAX_COUNT; i ++)
	{
        /**FScopeLock**/
		{
			//程序跳出花括号后自动解锁
			FScopeLock ScopeLock = FScopeLock(&CriticalSection);
			number++;
			UE_LOG(LogTemp, Warning, TEXT("Thread %s, %d"), *ThreadName, number);
		}
        /**FScopeLock**/
		FPlatformProcess::Sleep(0.01f);
	}
	return uint32();
}

void FThreadRunnable::Stop()
{
	UE_LOG(LogTemp, Warning, TEXT("Stop"));
	bIsRunning = false;
	bIsPause = false;
}

void FThreadRunnable::Exit()
{
}

void FThreadRunnable::Suspend(bool bIsSuspend)
{
	bIsPause = bIsSuspend;
}

void FThreadRunnable::PauseThread()
{
	bIsPause = true;
}

void FThreadRunnable::WakeupThread()
{
	bIsPause = false;
	//释放阻塞,当线程处于Wait时
	ThreadEvent->Trigger();
}

ThreadPool

​ 为了方便调试,新建C++空类。

在这里插入图片描述

在这里插入图片描述

​ 代码如下。

FMyWork.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

/**
 * 
 */
class SOCKETANDTHREAD_API FMyWork : public IQueuedWork
{
public:
	FMyWork();
	~FMyWork();
public:
	//这是真实线程实际工作的地方
	virtual void DoThreadedWork() override;
	
	//遗弃线程时执行的函数
	virtual void Abandon() override;
};

FMyWork.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FMyWork.h"

FMyWork::FMyWork()
{
	UE_LOG(LogTemp, Warning, TEXT("FMyWork"));
}

FMyWork::~FMyWork()
{
	UE_LOG(LogTemp, Warning, TEXT("~FMyWork"));
}

void FMyWork::DoThreadedWork()
{
	UE_LOG(LogTemp, Warning, TEXT("DoThreadedWork"));
	//保证释放内存
	Abandon();
}

void FMyWork::Abandon()
{
	delete this;
	UE_LOG(LogTemp, Warning, TEXT("Abandon"));
}

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if(!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if(GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if(GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if(!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
    
    
    
    
    /**ThreadPool**/
	//FQueuedThreadPool::Allocate:分配一个线程池
	FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	//Create:创建线程池的具体线程数量
	ThreadPool->Create(2);
	FMyWork* Work = new FMyWork;
	//AddQueuedWork:添加任务到队列当中执行
	ThreadPool->AddQueuedWork(Work);

	FPlatformProcess::Sleep(1.f);
	delete ThreadPool;
     /**ThreadPool**/
	
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if(ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if(RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if(RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

AsyncTask

​ 为了方便调试,新建C++空类。

在这里插入图片描述

在这里插入图片描述

  1. 复杂用法

FMyAsyncTask.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

/**
 * 
 */
class SOCKETANDTHREAD_API FMyAsyncTask
{
public:
	FMyAsyncTask();
	~FMyAsyncTask();
	friend class FAsyncTask<FMyAsyncTask>;
private:
	//任务是否可被遗弃,返回false,不可被遗弃
	FORCEINLINE bool CanAbandon() { return false; }
	//返回线程状态Id
	FORCEINLINE TStatId GetStatId() { return TStatId(); }
	//遗弃函数
	void Abandon();
	//线程工作内容函数,重要
	void DoWork();
};

FMyAsyncTask.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FMyAsyncTask.h"

FMyAsyncTask::FMyAsyncTask()
{
	
}

FMyAsyncTask::~FMyAsyncTask()
{
}

void FMyAsyncTask::Abandon()
{
}

void FMyAsyncTask::DoWork()
{
	UE_LOG(LogTemp, Warning, TEXT("DoWork"));
	FPlatformProcess::Sleep(5.f);
}

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

    /**AsyncTask**/
	FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	//StartSynchronousTask:在线程池运行此任务
	// Task->StartSynchronousTask();
	//StartBackgroundTask:将任务分配给后台线程池
	Task->StartBackgroundTask();
	//EnsureCompletion:等待任务,直到任务执行完成
	Task->EnsureCompletion();
	UE_LOG(LogTemp, Warning, TEXT("delete"));

	delete Task;
    /**AsyncTask**/
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}
  1. 简单用法

FMyAsyncTask.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

/**
 * 
 */
class SOCKETANDTHREAD_API FMyAsyncTask : public FNonAbandonableTask
{
public:
	FMyAsyncTask();
	~FMyAsyncTask();
	friend class FAutoDeleteAsyncTask<FMyAsyncTask>;
private:
	//返回线程状态Id
	FORCEINLINE TStatId GetStatId() { RETURN_QUICK_DECLARE_CYCLE_STAT(FMyAsyncTask, STATGROUP_ThreadPoolAsyncTasks); }
	//线程工作内容函数,重要
	void DoWork();
};

FMyAsyncTask.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "FMyAsyncTask.h"

FMyAsyncTask::FMyAsyncTask()
{
	
}

FMyAsyncTask::~FMyAsyncTask()
{
}

void FMyAsyncTask::DoWork()
{
	UE_LOG(LogTemp, Warning, TEXT("DoWork"));
	FPlatformProcess::Sleep(5.f);
}

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

    /**AsyncTask**/
	// FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	FAutoDeleteAsyncTask<FMyAsyncTask>* Task = new FAutoDeleteAsyncTask<FMyAsyncTask>;

	//StartSynchronousTask:在线程池运行此任务
	// Task->StartSynchronousTask();
	//StartBackgroundTask:将任务分配给后台线程池
	Task->StartBackgroundTask();
	UE_LOG(LogTemp, Warning, TEXT("delete"));
   	/**AsyncTask**/
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

TPromise和TFuture

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

	// FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	// FAutoDeleteAsyncTask<FMyAsyncTask>* Task = new FAutoDeleteAsyncTask<FMyAsyncTask>;
	//
	// //StartSynchronousTask:在线程池运行此任务
	// // Task->StartSynchronousTask();
	// //StartBackgroundTask:将任务分配给后台线程池
	// Task->StartBackgroundTask();
	// UE_LOG(LogTemp, Warning, TEXT("delete"));

    
    
    /**TPromise和TFuture**/
	TPromise<int32> Promise;
	//GetFuture:返回与此TPromise对象关联的TFuture对象
	TFuture<int32> Future = Promise.GetFuture();
	//CreateAndDispatchWhenReady:创新并在准备好时派发任务
	FFunctionGraphTask::CreateAndDispatchWhenReady([&Promise]()
	{
		FPlatformProcess::Sleep(10.f);
		Promise.SetValue(90);
	});
	
	//IsReady:检查TFuture对象是否有值被设置
	// while(!Future.IsReady())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("!IsReady"));
	// 	Promise.SetValue(36);
	// }
	//Wait:阻塞线程,直到TFuture的值有效
	// Future.Wait();
	//WaitFor:阻塞线程,若在等待时间内设置有效值,则返回true,否则返回false
	if(Future.WaitFor(FTimespan::FromSeconds(1)))
	{
		UE_LOG(LogTemp, Warning, TEXT("true"));
	}else
	{
		UE_LOG(LogTemp, Warning, TEXT("false"));
	}
	//Get:Get函数里封装Wait方法,所以在Get函数前,不需要使用Wait方法
	UE_LOG(LogTemp, Warning, TEXT("Value%d"), Future.Get());
    /**TPromise和TFuture**/
}

void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

Async

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"
#include "Async/Async.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

/**Async**/
//线程任务工作函数
bool CallFunc()
{
	FPlatformProcess::Sleep(5.f);
	return true;
}
//线程任务执行完调用此函数
bool CallFuncComplete()
{
	UE_LOG(LogTemp, Warning, TEXT("CallFuncComplete"));
	return true;
}
/**Async**/

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

	// FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	// FAutoDeleteAsyncTask<FMyAsyncTask>* Task = new FAutoDeleteAsyncTask<FMyAsyncTask>;
	//
	// //StartSynchronousTask:在线程池运行此任务
	// // Task->StartSynchronousTask();
	// //StartBackgroundTask:将任务分配给后台线程池
	// Task->StartBackgroundTask();
	// UE_LOG(LogTemp, Warning, TEXT("delete"));

	// TPromise<int32> Promise;
	// //GetFuture:返回与此TPromise对象关联的TFuture对象
	// TFuture<int32> Future = Promise.GetFuture();
	// //CreateAndDispatchWhenReady:创新并在准备好时派发任务
	// FFunctionGraphTask::CreateAndDispatchWhenReady([&Promise]()
	// {
	// 	FPlatformProcess::Sleep(10.f);
	// 	Promise.SetValue(90);
	// });
	
	//IsReady:检查TFuture对象是否有值被设置
	// while(!Future.IsReady())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("!IsReady"));
	// 	Promise.SetValue(36);
	// }
	//Wait:阻塞线程,直到TFuture的值有效
	// Future.Wait();
	//WaitFor:阻塞线程,若在等待时间内设置有效值,则返回true,否则返回false
	// if(Future.WaitFor(FTimespan::FromSeconds(1)))
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("true"));
	// }else
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("false"));
	// }
	// //Get:Get函数里封装Wait方法,所以在Get函数前,不需要使用Wait方法
	// UE_LOG(LogTemp, Warning, TEXT("Value%d"), Future.Get());
    /**Async**/
	//第一个参数,选择线程类型,可去源码查看;第二个参数是线程工作函数;第三个参数是线程执行完调用的函数
	auto MyFuture = Async(EAsyncExecution::Thread, &CallFunc, &CallFuncComplete);
	if(MyFuture.Get())
	{
		UE_LOG(LogTemp, Warning, TEXT("true"));
	}
    /**Async**/
}


void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

TaskGraph

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"
#include "Async/Async.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

//线程任务工作函数
bool CallFunc()
{
	FPlatformProcess::Sleep(5.f);
	return true;
}

//线程任务执行完调用此函数
bool CallFuncComplete()
{
	UE_LOG(LogTemp, Warning, TEXT("CallFuncComplete"));
	return true;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

	// FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	// FAutoDeleteAsyncTask<FMyAsyncTask>* Task = new FAutoDeleteAsyncTask<FMyAsyncTask>;
	//
	// //StartSynchronousTask:在线程池运行此任务
	// // Task->StartSynchronousTask();
	// //StartBackgroundTask:将任务分配给后台线程池
	// Task->StartBackgroundTask();
	// UE_LOG(LogTemp, Warning, TEXT("delete"));

	// TPromise<int32> Promise;
	// //GetFuture:返回与此TPromise对象关联的TFuture对象
	// TFuture<int32> Future = Promise.GetFuture();
	// //CreateAndDispatchWhenReady:创新并在准备好时派发任务
	// FFunctionGraphTask::CreateAndDispatchWhenReady([&Promise]()
	// {
	// 	FPlatformProcess::Sleep(10.f);
	// 	Promise.SetValue(90);
	// });

	//IsReady:检查TFuture对象是否有值被设置
	// while(!Future.IsReady())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("!IsReady"));
	// 	Promise.SetValue(36);
	// }
	//Wait:阻塞线程,直到TFuture的值有效
	// Future.Wait();
	//WaitFor:阻塞线程,若在等待时间内设置有效值,则返回true,否则返回false
	// if(Future.WaitFor(FTimespan::FromSeconds(1)))
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("true"));
	// }else
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("false"));
	// }
	// //Get:Get函数里封装Wait方法,所以在Get函数前,不需要使用Wait方法
	// UE_LOG(LogTemp, Warning, TEXT("Value%d"), Future.Get());
	// //第一个参数,选择线程类型,可去源码查看;第二个参数是线程工作函数;第三个参数是线程执行完调用的函数
	// auto MyFuture = Async(EAsyncExecution::Thread, &CallFunc, &CallFuncComplete);
	// if(MyFuture.Get())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("true"));
	// }
	/**TaskGraph**/
	FGraphEventRef Task1 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		UE_LOG(LogTemp, Warning, TEXT("Task1"));
	});
	//效果是,Task2在Task1执行完后再执行
	FGraphEventArray Task2GraphEvents;
	Task2GraphEvents.Add(Task1);
	FGraphEventRef Task2 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		FPlatformProcess::Sleep(5.f);
		UE_LOG(LogTemp, Warning, TEXT("Task2"));
	}, TStatId(), &Task2GraphEvents);
	//效果是,Task3在Task2执行完后再执行
	FGraphEventArray Task3GraphEvents;
	Task3GraphEvents.Add(Task1);
	FGraphEventRef Task3 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		UE_LOG(LogTemp, Warning, TEXT("Task3"));
	}, TStatId(), &Task3GraphEvents);
	//效果是,Task4在Task1、Task2、Task3执行完后再执行
	FGraphEventArray Task4GraphEvents;
	Task4GraphEvents.Add(Task1);
	Task4GraphEvents.Add(Task2);
	Task4GraphEvents.Add(Task3);
	FGraphEventRef Task4 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		FPlatformProcess::Sleep(1.f);
		UE_LOG(LogTemp, Warning, TEXT("Task4"));
	}, TStatId(), &Task4GraphEvents);
    /**TaskGraph**/
}


void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}

Socket

TCP

​ 为了方便调试,新建C++空类。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

​ 代码如下。

MySocketServer.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

class FRunnableThread;

/**
 * 
 */
class SOCKETANDTHREAD_API MySocketServer : public FRunnable
{
public:
	MySocketServer();
	MySocketServer(FString InThreadName);
	~MySocketServer();
public:
	//初始化Runnable对象
	virtual bool Init() override;

	//运行Runnable对象
	virtual uint32 Run() override;

	//停止Runnable对象
	virtual void Stop() override;

	//退出Runnable对象
	virtual void Exit() override;
private:
	FString ThreadName;
	FRunnableThread* RunnableThread;
public:
	FORCEINLINE FString GetThreadName() const { return ThreadName; }
};

MySocketServer.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketServer.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"

MySocketServer::MySocketServer()
{
}

MySocketServer::MySocketServer(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketServer::Init()
{
	return FRunnable::Init();
}

uint32 MySocketServer::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT(""));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(9999);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		//绑定地址和端口
		Socket->Bind(*Addr);
		//端口监听
		if (Socket->Listen(128))
		{
			while (true)
			{
				//接收客户端消息,是阻塞方法
				FSocket* ClientSocket = Socket->Accept(TEXT(""));
				uint8 Buf[1024]{0};
				int32 ByteRead = 0;
				//接收客户端消息
				ClientSocket->Recv(Buf, 1024, ByteRead);
				FString Msg = UTF8_TO_TCHAR(reinterpret_cast<char *>(Buf));
				UE_LOG(LogTemp, Warning, TEXT("Msg=%s || Len = %d"), *Msg, ByteRead);
			}
		}
	}
	return uint32();
}

void MySocketServer::Stop()
{
	FRunnable::Stop();
}

void MySocketServer::Exit()
{
	FRunnable::Exit();
}

MySocketServer::~MySocketServer()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

MySocketClient.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"

class FRunnableThread;



/**
 * 
 */
class SOCKETANDTHREAD_API MySocketClient : FRunnable
{
public:
	MySocketClient();
	MySocketClient(FString InThreadName);
	~MySocketClient();
public:
	//初始化Runnable对象
	virtual bool Init() override;

	//运行Runnable对象
	virtual uint32 Run() override;

	//停止Runnable对象
	virtual void Stop() override;

	//退出Runnable对象
	virtual void Exit() override;
private:
	FString ThreadName;
	FRunnableThread* RunnableThread;
public:
	FORCEINLINE FString GetThreadName() const { return ThreadName; }
};

MySocketClient.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketClient.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"

MySocketClient::MySocketClient()
{
}

MySocketClient::MySocketClient(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketClient::Init()
{
	return FRunnable::Init();
}

uint32 MySocketClient::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT(""));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(9999);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		if (Socket->Connect(*Addr))
		{
			FString Msg = "Hello Server";
			int32 SendSize = 0;
			Socket->Send(reinterpret_cast<uint8*>(TCHAR_TO_UTF8(*Msg)), Msg.Len(), SendSize);
			FPlatformProcess::Sleep(1.f);
			Socket->Close();
			SocketSubsystem->DestroySocket(Socket);
			
		}
	}
	return uint32();
}

void MySocketClient::Stop()
{
	FRunnable::Stop();
}

void MySocketClient::Exit()
{
	FRunnable::Exit();
}

MySocketClient::~MySocketClient()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

STGameInstanceSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "STGameInstanceSubsystem.generated.h"

class FThreadRunnable;
class FRunnableThread;

/**
 * 
 */
UCLASS()
class SOCKETANDTHREAD_API USTGameInstanceSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	//这个子系统是否应该被创建
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

	//执行这个系统实例的初始化
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;

	//执行这个系统实例的销毁
	virtual void Deinitialize() override;
	//对实例获取的一种封装
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	static USTGameInstanceSubsystem* Get();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartThread();
	//线程退出
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StopThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void SuspendThread(bool bIsSuspend);
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void PauseThread();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void WakeupThread();
	//强制线程退出
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void Shutdown(bool bShouldWait);
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
    /**TCP**/
	void StartSocketServer();
	UFUNCTION(BlueprintCallable, Category="STGameSubsystem")
	void StartSocketClient();
     /**TCP**/

	// bool CallFunc();
private:
	//单例模式
	static USTGameInstanceSubsystem* GameInstanceSubsystem;
	TSharedPtr<FThreadRunnable> ThreadRunnable;
	FRunnableThread* RunnableThread;  //Runnable对象的接口,此接口是用于管理线程运行生命周期的方法
};

STGameInstanceSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "STGameInstanceSubsystem.h"
#include "FThreadRunnable.h"
#include "HAL/RunnableThread.h"
#include "HAL/Runnable.h"
#include "FMyWork.h"
#include "FMyAsyncTask.h"
#include "Async/Async.h"
#include "MySocketServer.h"
#include "MySocketClient.h"

USTGameInstanceSubsystem* USTGameInstanceSubsystem::GameInstanceSubsystem = nullptr;

bool USTGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	if (!Super::ShouldCreateSubsystem(Outer))
	{
		return false;
	}
	return true;
}

void USTGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp, Warning, TEXT("Initialize"));
	if (GameInstanceSubsystem == nullptr)
	{
		GameInstanceSubsystem = this;
	}
}

void USTGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
	if (GameInstanceSubsystem)
	{
		GameInstanceSubsystem = nullptr;
	}
}

USTGameInstanceSubsystem* USTGameInstanceSubsystem::Get()
{
	if (!GameInstanceSubsystem)
	{
		UE_LOG(LogTemp, Error, TEXT("USTGameInstanceSubsystem 实例不存在"));
		return nullptr;
	}
	return GameInstanceSubsystem;
}

//线程任务工作函数
bool CallFunc()
{
	FPlatformProcess::Sleep(5.f);
	return true;
}

//线程任务执行完调用此函数
bool CallFuncComplete()
{
	UE_LOG(LogTemp, Warning, TEXT("CallFuncComplete"));
	return true;
}

void USTGameInstanceSubsystem::StartThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StartThread"));
	//创建共享指针
	//MakeShareable参数是T的指针
	// //MakeShared的参数是T构造函数参数
	// ThreadRunnable = MakeShared<FThreadRunnable>(TEXT("ThreadRunnable"));
	// //FRunnableThread::Create():工厂函数,创建一个具体堆栈大小和线程优先级的线程,创建好线程之后就会执行Run函数
	// RunnableThread = FRunnableThread::Create(ThreadRunnable.Get(), *(ThreadRunnable->GetThreadName()));
	// for(int32 i = 0; i < 2; i ++)
	// {
	// 	//仅用于演示,有内存泄露问题
	// 	FThreadRunnable* Temp = new FThreadRunnable(FString::Printf(TEXT("TD%d"),i));
	// 	FRunnableThread::Create(Temp, *(Temp->GetThreadName()));
	// }
	// //FQueuedThreadPool::Allocate:分配一个线程池
	// FQueuedThreadPool* ThreadPool = FQueuedThreadPool::Allocate();
	// //Create:创建线程池的具体线程数量
	// ThreadPool->Create(2);
	// FMyWork* Work = new FMyWork;
	// //AddQueuedWork:添加任务到队列当中执行
	// ThreadPool->AddQueuedWork(Work);
	//
	// FPlatformProcess::Sleep(1.f);
	// delete ThreadPool;

	// FAsyncTask<FMyAsyncTask>* Task = new FAsyncTask<FMyAsyncTask>;
	// FAutoDeleteAsyncTask<FMyAsyncTask>* Task = new FAutoDeleteAsyncTask<FMyAsyncTask>;
	//
	// //StartSynchronousTask:在线程池运行此任务
	// // Task->StartSynchronousTask();
	// //StartBackgroundTask:将任务分配给后台线程池
	// Task->StartBackgroundTask();
	// UE_LOG(LogTemp, Warning, TEXT("delete"));

	// TPromise<int32> Promise;
	// //GetFuture:返回与此TPromise对象关联的TFuture对象
	// TFuture<int32> Future = Promise.GetFuture();
	// //CreateAndDispatchWhenReady:创新并在准备好时派发任务
	// FFunctionGraphTask::CreateAndDispatchWhenReady([&Promise]()
	// {
	// 	FPlatformProcess::Sleep(10.f);
	// 	Promise.SetValue(90);
	// });

	//IsReady:检查TFuture对象是否有值被设置
	// while(!Future.IsReady())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("!IsReady"));
	// 	Promise.SetValue(36);
	// }
	//Wait:阻塞线程,直到TFuture的值有效
	// Future.Wait();
	//WaitFor:阻塞线程,若在等待时间内设置有效值,则返回true,否则返回false
	// if(Future.WaitFor(FTimespan::FromSeconds(1)))
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("true"));
	// }else
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("false"));
	// }
	// //Get:Get函数里封装Wait方法,所以在Get函数前,不需要使用Wait方法
	// UE_LOG(LogTemp, Warning, TEXT("Value%d"), Future.Get());
	// //第一个参数,选择线程类型,可去源码查看;第二个参数是线程工作函数;第三个参数是线程执行完调用的函数
	// auto MyFuture = Async(EAsyncExecution::Thread, &CallFunc, &CallFuncComplete);
	// if(MyFuture.Get())
	// {
	// 	UE_LOG(LogTemp, Warning, TEXT("true"));
	// }

	FGraphEventRef Task1 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		UE_LOG(LogTemp, Warning, TEXT("Task1"));
	});
	//效果是,Task2在Task1执行完后再执行
	FGraphEventArray Task2GraphEvents;
	Task2GraphEvents.Add(Task1);
	FGraphEventRef Task2 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		FPlatformProcess::Sleep(5.f);
		UE_LOG(LogTemp, Warning, TEXT("Task2"));
	}, TStatId(), &Task2GraphEvents);
	//效果是,Task3在Task2执行完后再执行
	FGraphEventArray Task3GraphEvents;
	Task3GraphEvents.Add(Task1);
	FGraphEventRef Task3 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		UE_LOG(LogTemp, Warning, TEXT("Task3"));
	}, TStatId(), &Task3GraphEvents);
	//效果是,Task4在Task1、Task2、Task3执行完后再执行
	FGraphEventArray Task4GraphEvents;
	Task4GraphEvents.Add(Task1);
	Task4GraphEvents.Add(Task2);
	Task4GraphEvents.Add(Task3);
	FGraphEventRef Task4 = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
	{
		FPlatformProcess::Sleep(1.f);
		UE_LOG(LogTemp, Warning, TEXT("Task4"));
	}, TStatId(), &Task4GraphEvents);
}


void USTGameInstanceSubsystem::StopThread()
{
	UE_LOG(LogTemp, Warning, TEXT("StopThread"));
	//IsValid:检车共享指针是否还存在引用对象
	if (ThreadRunnable.IsValid())
	{
		ThreadRunnable->Stop();
	}
	if (RunnableThread)
	{
		//WaitForCompletion:暂停访问,等待线程工作执行完成
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

void USTGameInstanceSubsystem::SuspendThread(bool bIsSuspend)
{
	// ThreadRunnable->Suspend(bIsSuspend);
	RunnableThread->Suspend(bIsSuspend);
}

void USTGameInstanceSubsystem::PauseThread()
{
	ThreadRunnable->PauseThread();
}

void USTGameInstanceSubsystem::WakeupThread()
{
	ThreadRunnable->WakeupThread();
}

void USTGameInstanceSubsystem::Shutdown(bool bShouldWait)
{
	if (RunnableThread)
	{
		RunnableThread->Kill(bShouldWait);
	}
}
 /**TCP**/
void USTGameInstanceSubsystem::StartSocketServer()
{
	new MySocketServer("asd");
}

void USTGameInstanceSubsystem::StartSocketClient()
{
	new MySocketClient("fff");
}
 /**TCP**/

​ 蓝图中关卡蓝图代码如下。

在这里插入图片描述

UDP

MySocketClient.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketClient.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"

MySocketClient::MySocketClient()
{
}

MySocketClient::MySocketClient(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketClient::Init()
{
	return FRunnable::Init();
}

uint32 MySocketClient::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_DGram, TEXT(""));
	UE_LOG(LogTemp, Warning, TEXT("Start Client"));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(10000);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		while (true)
		{
			FString Msg = "Hello Server";
			int32 SendSize = 0;
			Socket->SendTo(reinterpret_cast<uint8*>(TCHAR_TO_UTF8(*Msg)), Msg.Len(), SendSize, *Addr);
			uint8 Buf[1024]{0};
			int32 ByteRead = 0;
			bool bIsSuccess = Socket->RecvFrom(Buf, 1024, ByteRead, *Addr);
			if (bIsSuccess)
			{
				UE_LOG(LogTemp, Warning, TEXT("Client Ok"));
				FString NewMsg = UTF8_TO_TCHAR(reinterpret_cast<char*>(Buf));
				UE_LOG(LogTemp, Warning, TEXT("Msg = %s || Len = %d"), *NewMsg, ByteRead);
			}
			FPlatformProcess::Sleep(1.f);
		}
	
	}
	return uint32();
}

void MySocketClient::Stop()
{
	FRunnable::Stop();
}

void MySocketClient::Exit()
{
	FRunnable::Exit();
}

MySocketClient::~MySocketClient()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

MySocketServer.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketServer.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"

MySocketServer::MySocketServer()
{
}

MySocketServer::MySocketServer(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketServer::Init()
{
	return FRunnable::Init();
}

uint32 MySocketServer::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	// FSocket* Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT(""));
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_DGram, TEXT(""));
	UE_LOG(LogTemp, Warning, TEXT("Start Server"));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(10000);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		//绑定地址和端口
		Socket->Bind(*Addr);
		Socket->SetReuseAddr();
		//端口监听
		// if (Socket->Listen(128))
		// {
		while (true)
		{
			uint8 Buf[1024]{0};
			int32 ByteRead = 0;
			//接收客户端消息
			TSharedPtr<FInternetAddr> ClientAddr = SocketSubsystem->CreateInternetAddr();
			bool bIsSuccess = Socket->RecvFrom(Buf, 1024, ByteRead, *ClientAddr);
			if (bIsSuccess)
			{
				UE_LOG(LogTemp, Warning, TEXT("Server Ok"));
				FString Msg = UTF8_TO_TCHAR(reinterpret_cast<char*>(Buf));
				UE_LOG(LogTemp, Warning, TEXT("Msg = %s || Len = %d"), *Msg, ByteRead);
				FString NewMsg = TEXT("Hello Client");
				int32 SendSize = 0;
				Socket->SendTo(reinterpret_cast<uint8*>(TCHAR_TO_UTF8(*NewMsg)), NewMsg.Len(), SendSize, *ClientAddr);
			}
		}
		// }
	}
	return uint32();
}

void MySocketServer::Stop()
{
	FRunnable::Stop();
}

void MySocketServer::Exit()
{
	FRunnable::Exit();
}

MySocketServer::~MySocketServer()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

粘包处理

​ TCP粘包是指在基于TCP协议的数据传输过程中,发送方发送的多个数据包在到达接收方时粘连成一包的现象。这里通过添加包头来解决问题。

MySocketServer.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketServer.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"

MySocketServer::MySocketServer()
{
}

MySocketServer::MySocketServer(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketServer::Init()
{
	return FRunnable::Init();
}

uint32 MySocketServer::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT(""));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(9999);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		//绑定地址和端口
		Socket->Bind(*Addr);
		//端口监听
		if (Socket->Listen(128))
		{
			//接收客户端消息,是阻塞方法
			FSocket* ClientSocket = Socket->Accept(TEXT(""));
			while (true)
			{
			if (ClientSocket)
			{
				uint8 Buf[1024]{0};
				uint8* Data = Buf;
				int32 HeadSize = sizeof FSimpleHead;
				int32 ByteRead = 0;
				int32 Flag = HeadSize;
				bool bIsSuccess = ClientSocket->Recv(Data, HeadSize, ByteRead);
				FSimpleHead& Head = *reinterpret_cast<FSimpleHead*>(Data);
				int32 DataSize = Head.DataSize;
				while (DataSize > 0 && bIsSuccess)
				{
					Data += Flag;
					bIsSuccess = ClientSocket->Recv(Data, DataSize, ByteRead);
					Flag = ByteRead;
					DataSize -= ByteRead;
				}
				Data = Buf + HeadSize;
				FString Msg = UTF8_TO_TCHAR(reinterpret_cast<char* >(Data));
				UE_LOG(LogTemp, Warning, TEXT("Msg = %s"), *Msg);
			}
			}
		}
	}
	return uint32();
}

void MySocketServer::Stop()
{
	FRunnable::Stop();
}

void MySocketServer::Exit()
{
	FRunnable::Exit();
}

MySocketServer::~MySocketServer()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}

MySocketClient.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MySocketClient.h"
#include "HAL/Runnable.h"
#include "HAL/RunnableThread.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "MySocketServer.h"

MySocketClient::MySocketClient()
{
}

MySocketClient::MySocketClient(FString InThreadName)
{
	ThreadName = InThreadName;
	RunnableThread = FRunnableThread::Create(this, *ThreadName);
}

bool MySocketClient::Init()
{
	return FRunnable::Init();
}

uint32 MySocketClient::Run()
{
	//ISocketSubsystem::Get:获取Socket子系统封装
	ISocketSubsystem* SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
	//CreateSocket:选择TCP创建Socket
	FSocket* Socket = SocketSubsystem->CreateSocket(NAME_Stream, TEXT(""));
	//CreateInternetAddr:创建地址共享指针
	TSharedPtr<FInternetAddr> Addr = SocketSubsystem->CreateInternetAddr();
	Addr->SetPort(9999);
	bool bIsValid = false;
	Addr->SetIp(TEXT("127.0.0.1"), bIsValid);
	if (bIsValid)
	{
		if (Socket->Connect(*Addr))
		{
			FString SendMsg = TEXT("ASDFGHJKLqwertyuiopzxcvbnm");
			for(int32 i = 0; i < 20; i ++)
			{
				int32 ByteSend = 0;
				int32 StartPos = 0;
				TArray<uint8> Buffer;
				FSimpleHead Head;
				Head.DataSize = SendMsg.GetCharArray().Num();
				//AddUninitialized:数组初始化的函数
				Buffer.AddUninitialized(sizeof FSimpleHead + Head.DataSize);
				FMemory::Memcpy(&Buffer[StartPos], &Head, sizeof FSimpleHead);
				StartPos += sizeof FSimpleHead;
				for(auto Val : SendMsg.GetCharArray())
				{
					FMemory::Memcpy(&Buffer[StartPos], &Val, 1);
					StartPos += 1;
				}
				Socket->Send(Buffer.GetData(), Buffer.Num(), ByteSend);
				FPlatformProcess::Sleep(0.1f);
			}
		}
	}
	return uint32();
}

void MySocketClient::Stop()
{
	FRunnable::Stop();
}

void MySocketClient::Exit()
{
	FRunnable::Exit();
}

MySocketClient::~MySocketClient()
{
	if (this)
	{
		this->Stop();
		delete this;
	}
	if (RunnableThread)
	{
		RunnableThread->WaitForCompletion();
		delete RunnableThread;
		RunnableThread = nullptr;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值