最近学习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()
{
}
在关卡蓝图中写入如下代码。
二、线程暂停
- 变量方式
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;
}
/**变量方式**/
在关卡蓝图中写入如下代码。
- 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方法**/
}
- 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++
空类。
- 复杂用法
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);
}
}
- 简单用法
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;
}
}