UE4中使用多线程的有两种方式,一种方式就是使用FRunnable和FRunnableThread,另一种方式是Task Graph System。Task Graph System有时会占用游戏线程的时间,适合用在简单的计算或者需要开多个线程的情况。FRunnable适用于复杂运算。但是当创建太多线程后,有可能达到CPU的上限,这些线程就会为了抢占CPU的时间而彼此阻碍。UE4提供了FQueuedThreadPool来限制最大的线程数量。

  这种方式需要定义一个类继承自FRunnable,并且实现Init,Run,Stop,Exit。还需要一个FRunnableThread对象来创建和销毁线程。

  具体代码:

  1. #pragma once
  2.  
  3. #include "CoreMinimal.h"
  4. #include "Runnable.h"
  5. #include "RunnableThread.h"
  6.  
  7. class TESTTARRAY_API AudioRecordThread : public FRunnable
  8. {
  9. public:
  10. AudioRecordThread(FString threadName);
  11. ~AudioRecordThread();
  12.  
  13. //暂停线程
  14. void PauseThread();
  15. //继续线程
  16. void ContinueThread();
  17. //停止线程
  18. void StopThread();
  19.  
  20. bool IsThreadPaused();
  21. bool IsThreadKilled();
  22.  
  23. private:
  24. FRunnableThread* Thread;
  25. FThreadSafeCounter StopTaskCounter;
  26. FCriticalSection m_mutex;
  27. public:
  28. //override Frunnable Function
  29. virtual bool Init() override;
  30. virtual uint32 Run() override;
  31. virtual void Stop() override;
  32. virtual void Exit() override;
  33.  
  34. private:
  35. FThreadSafeBool m_Kill;
  36. FThreadSafeBool m_Pause;
  37. };
  1. #include "AudioRecordThread.h"
  2. #include "Engine.h"
  3.  
  4. AudioRecordThread::AudioRecordThread(FString threadName) : StopTaskCounter()
  5. {
  6. m_Kill = false;
  7. m_Pause = false;
  8. Thread = FRunnableThread::Create(this, *threadName, , TPri_BelowNormal);
  9. }
  10.  
  11. AudioRecordThread::~AudioRecordThread()
  12. {
  13. if (Thread)
  14. {
  15. delete Thread;
  16. Thread = nullptr;
  17. }
  18. }
  19.  
  20. void AudioRecordThread::PauseThread()
  21. {
  22. m_Pause = true;
  23. }
  24.  
  25. void AudioRecordThread::ContinueThread()
  26. {
  27. m_Pause = false;
  28. }
  29.  
  30. void AudioRecordThread::StopThread()
  31. {
  32. Stop();
  33. if (Thread)
  34. {
  35. Thread->WaitForCompletion();
  36. }
  37. }
  38. //需要注意的是在其他线程不能对UObject进行操作,不能使用TimerManager,不能使用DrawDebugLine。
  39.  
  40. bool AudioRecordThread::IsThreadPaused()
  41. {
  42. return (bool)m_Pause;
  43. }
  44.  
  45. bool AudioRecordThread::IsThreadKilled()
  46. {
  47. return (bool)m_Kill;
  48. }
  49.  
  50. bool AudioRecordThread::Init()
  51. {
  52. GEngine->AddOnScreenDebugMessage(-, 10.0f, FColor::Yellow, TEXT("AudioRecordThreadInit"));
  53. return true;
  54. }
  55.  
  56. uint32 AudioRecordThread::Run()
  57. {
  58. //使用该函数Sleep
  59. FPlatformProcess::Sleep(0.03);
  60. while (StopTaskCounter.GetValue() == && !m_Kill)
  61. {
  62. if (m_Pause)
  63. {
  64. GEngine->AddOnScreenDebugMessage(-, 10.0f, FColor::Yellow, TEXT("AudioRecordThreadPause"));
  65. if (m_Kill)
  66. {
  67. return ;
  68. }
  69. }
  70. else
  71. {
  72. GEngine->AddOnScreenDebugMessage(-, 10.0f, FColor::Yellow, TEXT("AudioRecordThreadLoop"));
  73.  
  74. m_mutex.Lock();
  75. //需要同步处理的内容
  76.  
  77. m_mutex.Unlock();
  78.  
  79. FPlatformProcess::Sleep(0.01);
  80. }
  81. }
  82. return ;
  83. }
  84.  
  85. void AudioRecordThread::Stop()
  86. {
  87. StopTaskCounter.Increment();
  88. m_Kill = true;
  89. m_Pause = false;
  90. GEngine->AddOnScreenDebugMessage(-, 10.0f, FColor::Yellow, TEXT("AudioRecordThreadStop"));
  91. }
  92.  
  93. void AudioRecordThread::Exit()
  94. {
  95. GEngine->AddOnScreenDebugMessage(-, 10.0f, FColor::Yellow, TEXT("AudioRecordThreadExit"));
  96. }

  创建线程:

  1. m_AudioRecordThread = new AudioRecordThread("AudioRecordThread1");

,  构造函数中会用FRunnableThread::Create来创建线程。

  停止线程:

  1. if (m_AudioRecordThread)
  2. {
  3. m_AudioRecordThread->StopThread();
  4. delete m_AudioRecordThread;
  5. m_AudioRecordThread = nullptr;
  6. }

  在StopThread中会调用Stop来控制相关状态量完成线程循环,Thread->WaitForCompletion(),会使调用StopThread的线程即主线程悬挂,当线程循环完成后继续,继续后删除m_AudioRecordThread对象。需要注意的是这样停止线程会调用两次Stop函数,所以Stop中最好只执行控制线程循环停止的状态量。

  使用FPlatformProcess::Sleep(0.03)来等待,避免线程占用过多的资源。

  线程锁:

    使用m_mutex.Lock();和m_mutex.Unlock();包裹住需要同步的代码即可。

  需要注意的是在其他线程不能对UObject进行操作,不能使用TimerManager,不能使用DrawDebugLine。要在游戏线程执行代码可以这样用:

  1. #include "Async.h"
  2. ...
  3. AsyncTask(ENamedThreads::GameThread, []() {
  4. // code to execute on game thread here
  5. });

  另外我这里使用多线程是做录音相关功能,用到了AudioClient.h这个头文件,因为这个文件用到了windows的东西,所以用在UE4里会报错,所以需要把这个头文件放到CPP里包含,用到的struct使用前置声明。

  

UE4 多线程(一)的更多相关文章

  1. [UE4]多线程开关,开启的解决方案

    像这样直接获取值就会被警告. 解决方法:定义一个变量speed,然后在“Blueprint Update Animation”事件中赋值给这个变量. 这样就不会被警告了. 另外一种解决方法:就是关掉多 ...

  2. 《Exploring in UE4》多线程机制详解[原理分析]

    转自:https://zhuanlan.zhihu.com/c_164452593 目录一.概述二."标准"多线程三.AsyncTask系统3.1 FQueuedThreadPoo ...

  3. UE4 Sockets多线程TCP通信

    转自:https://blog.csdn.net/zilisen/article/details/75007447 一.简介 UE4引擎是提供了Sockets模块和Networking模块的,博主在研 ...

  4. UE4 Socket多线程非阻塞通信

    转自:https://blog.csdn.net/lunweiwangxi3/article/details/50468593 ue4自带的Fsocket用起来依旧不是那么的顺手,感觉超出了我的理解范 ...

  5. UE4的多线程

    1. 源代码 AsyncWork.h 2. 多线程的使用 参考文档:https://wiki.unrealengine.com/Using_AsyncTasks 当我们需要执行一个需要很长时间的任务时 ...

  6. 【UE4 C++ 基础知识】<12> 多线程——FRunnable

    概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...

  7. 【UE4 C++ 基础知识】<13> 多线程——TaskGraph

    概述 TaskGraph 系统是UE4一套抽象的异步任务处理系统 TaskGraph 可以看作一种"基于任务的并行编程"设计思想下的实现 通过TaskGraph ,可以创建任意多线 ...

  8. 【UE4 C++ 基础知识】<14> 多线程——AsyncTask

    概念 AsyncTask AsyncTask 系统是一套基于线程池的异步任务处理系统.每创建一个AsyncTas,都会被加入到线程池中进行执行 AsyncTask 泛指 FAsyncTask 和 FA ...

  9. 《图解UE4渲染体系》Part 1 多线程渲染

    上回书<Part 0 引擎基础>说到,我们粗略地知道UE4是以哪些类来管理一个游戏场景里的数据的,但这仅仅是我们开始探索UE4渲染体系的一小步. 本回主要介绍UE4渲染体系中比较宏观顶层的 ...

随机推荐

  1. linux防火墙之 ufw

    Usage: ufw COMMAND Commands: enable enables the firewall 开启ufw防火墙 disable disables the firewall 禁用防火 ...

  2. 一个IC软件工程师的2017年终工作总结

    相比2016年的波澜起伏,2017多了一份平静和清淡.不过,平静的生活下,总有一颗飞向远方的心. 在这一年将近结束的时候,总结一下自己的工作,生活和学习.也顺便展望一下未来的2018,看看有哪些 美好 ...

  3. Java基础day01

    linux:1免费 开源的操作系统,Java主要是服务器端的开发 2与window,目录结构.安全性比后者高 3常用命令 pwd.ls.cd:vi(打开一个记事本若没有就新建一个记事本) 绝对路径:都 ...

  4. 在macOS上通过pyenv安装和切换多版本Python

    1. 安装homebrew 官网 http://brew.sh/index_zh-cn.html 打开终端,在终端中粘贴如下脚本 /usr/bin/ruby -e "$(curl -fsSL ...

  5. HTTPS、证书与使用Charles抓包

    .p1 { margin: 0.0px 0.0px 0.0px 0.0px; font-size: 14.0px; font-family: "Helvetica Neue", & ...

  6. 关于javascript代码优化的8点建议

    前面的话 本文将详细介绍JS编程风格的几个要点 松耦合 当修改一个组件而不需要更改其他组件时,就做到了松耦合 1.将JS从CSS中抽离:不要使用CSS表达式 //不好的做法 .box{width: e ...

  7. python3之装饰器

    1.装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处 ...

  8. I/O模型详细解析

    内核空间和用户空间:由于操作系统都包括内核空间和用户空间(或者说内核态和用户态),内核空间主要存放的是内核代码和数据,是供系统进程使用的空间.而用户空间主要存放的是用户代码和数据,是供用户进程使用的空 ...

  9. SAP Fiori应用的三种部署方式

    封面图片来自Google搜索,关键字: Fiori Deployment 方式1 On premise环境下以BSP应用作为Fiori应用部署和运行的载体 在SAP成都labs我曾经担任过CRM这几个 ...

  10. [原创]在Centos7.2上源码安装PHP、Nginx、Zentao禅道

    版本 操作系统:CentOS Linux release 7.2.1511 (Core) PHP:5.6.33 Nginx:1.12.2 MySQL:5.6.38(192.168.1.103的Wind ...