`

Cocos2d-x优化中多线程并发访问

 
阅读更多

多线程并发访问在Cocos2d-x引擎中用的不是很多,这主要是因为中整个结构设计没有采用多线程。源自于Objective-C的Ref对象,需要使用AutoreleasePool进行内存管理,AutoreleasePool是非线程安全的,所有不推荐在子多线程中调用Ref对象的retain()、 release()和autorelease()等函数。另外,OpenGL上下文对象也是不支持线程安全的。
但是有的时候我们需要异步加载一些资源,例如:加载图片纹理、声音的预处理和网络请求数据等。如果是异步加载图片纹理我们可以使用第20.4.4一节介绍的内容。但声音的预处理和网络请求数据等就需要自己通过多线程技术实现了。
Cocos2d-x引擎也提供了多线程技术,Cocos2d-x 3.x之前是使用第三方的pthread技术。Cocos2d-x 3.x之后使用C++11新规范中的std::thread多线程技术,std::thread使用起来比较简单。


1.std::thread多线程技术
std::thread是C++11 引入了一个新的线程库,它提供了线程管理相关函数,std::thread库中还提供了std::mutex(互斥量),通过std::mutex可以实现线程同步。
启动一个新的线程非常简单,当我们创建一个 std::thread 对象时候,它便会自行启动。创建线程std::thread 对象时,可以提供该线程的回调函数。下面代码实现了创建线程和线程函数的回调:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. #include <thread>  
  2. #include <iostream>  
  3.   
  4.   
  5. void callfn(){                                                              ①  
  6.     std::cout << "Hello thread! " << std::endl;  
  7. }  
  8. int main(){  
  9.     std::thread t1(callfn);                                             ②  
  10.         t1.join();                                                              ③  
  11.     return 0;  
  12. }  



上述代码第②行是创建t1线程对象,它的参数是函数指针callfn,如果需要,我们还可以为回调函数提供参数。代码第①行是回调函数的定义。第③行代码t1.join()是将子线程与主线程合并,这种合并能够使子线程执行完成后才能继续执行主线程,这是为了避免子线程还在执行,主线程已经执行结束而撤销。
创建线程还可以使用堆的方式分配内存,代码如下: 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. void callfn(){  
  2.     std::cout << "Hello thread! " << std::endl;  
  3. }  
  4. int main(){  
  5.     std::thread* t1 = new  std::thread(callfn);                                 ①  
  6.     t1->join();  
  7.     delete  t1;                                                             ②  
  8.     t1 = nullptr;                                                           ③  
  9.     return 0;  
  10. }  



上述代码第①行是通过堆方式分配内存,即通过new运算符创建动态线程对象。因此需要在使用完成的情况下释放对象,我们在代码第②行使用deletet1语句释放,释放完成还以通过代码第③行t1 = nullptr设置指针变量,这样可以防止“野指针”。


2.异步预处理声音
std::thread线程Cocos2d-x中有很多现实的应用,异步预处理声音,异步加载一些资源资源文件,异步加载图片纹理Cocos2d-x为我们提供了API,但是它们异步加载需要我们自己实现。下面我们介绍一下异步预处理声音。
我们在前面20.5一节介绍了声音预处理和清除,在那一节中预处理声音是同步的,它会导致堵塞主线程,使用户的感觉会“卡”了一下。如果这个“卡”比较长,我们解决主线程阻塞问题,改善用户体验,我们可以异步预处理声音。
我们在20.5一节的案例中采用std::thread线程异步预处理声音,我们可以在AppDelegate中进行异步加载,修改之后的AppDelegate.h代码如下:
#include "cocos2d.h"
#include "SimpleAudioEngine.h"


using namespace CocosDenshion;


class  AppDelegate : private cocos2d::Application
{
private:
std::thread *_loadingAudioThread;
void loadingAudio();


public:
AppDelegate();
virtual ~AppDelegate();
 
   … …
};
我们在第①行声明了私有的std::thread线程指针变量_loadingAudioThread。第②代码是声明了私有的异步预处理声音函数loadingAudio()。
修改之后的AppDelegate.cpp代码如下:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. include "AppDelegate.h"  
  2. #include "HelloWorldScene.h"  
  3.   
  4.   
  5. USING_NS_CC;  
  6.   
  7.   
  8. AppDelegate::AppDelegate()   
  9. {  
  10.     _loadingAudioThread = new std::thread(&AppDelegate::loadingAudio,this);             ①  
  11. }  
  12.   
  13.   
  14. AppDelegate::~AppDelegate()   
  15. {  
  16.     _loadingAudioThread->join();                                         ②  
  17.     CC_SAFE_DELETE(_loadingAudioThread);                                    ③  
  18. }  
  19.   
  20.   
  21. bool AppDelegate::applicationDidFinishLaunching() {  
  22.    … …  
  23.     return true;  
  24. }  
  25. void AppDelegate::applicationDidEnterBackground() {  
  26.     Director::getInstance()->stopAnimation();  
  27.     SimpleAudioEngine::getInstance()->pauseBackgroundMusic();  
  28. }  
  29. void AppDelegate::applicationWillEnterForeground() {  
  30.     Director::getInstance()->startAnimation();  
  31.     SimpleAudioEngine::getInstance()->resumeBackgroundMusic();  
  32. }  
  33.   
  34.   
  35. void AppDelegate::loadingAudio()                                            ④  
  36. {  
  37.     //初始化 音乐  
  38.     SimpleAudioEngine::getInstance()->preloadBackgroundMusic("sound/Jazz.mp3");  
  39.     SimpleAudioEngine::getInstance()->preloadBackgroundMusic("sound/Synth.mp3");  
  40.     //初始化 音效  
  41.     SimpleAudioEngine::getInstance()->preloadEffect("sound/Blip.wav");  
  42. }  



上述代码第①行是在构造函数里创建线程对象,创建线程对象代码也可以放置到 AppDelegate::applicationDidFinishLaunching()函数中,我们根据需要在合适的地方创建。
第②行代码_loadingAudioThread->join()是合并线程到主线程,这个处理是在析构函数中调用的,join()函数一般是在线程处理完成后调用,我们可以在析构函数中调用,也可以在一些退出函数(如Layer的onExit函数)中调用。由于是_loadingAudioThread动态对象指针类型,需要释放对象,我们可以通过第③行代码CC_SAFE_DELETE(_loadingAudioThread)释放。CC_SAFE_DELETE宏的作用如下:
delete_loadingAudioThread;
_loadingAudioThread = nullptr;

第④行代码AppDelegate::loadingAudio()定义了线程回调函数,我们在这个函数中预处理声音。

 

 

更多内容请关注国内第一本Cocos2d-x 3.2版本图书《Cocos2d-x实战:C++卷》
本书交流讨论网站:http://www.cocoagame.net
更多精彩视频课程请关注智捷课堂Cocos课程:http://v.51work6.com
欢迎加入Cocos2d-x技术讨论群:257760386
欢迎关注智捷iOS课堂微信公共平台

分享到:
评论

相关推荐

    Cocos2d-x 中使用多线程

    本文将深入探讨Cocos2d-x中如何创建和管理多线程。 首先,我们要了解线程的基本概念。线程是操作系统分配CPU时间的基本单位,一个进程中可以有多个线程并发执行,每个线程负责不同的任务。在Cocos2d-x中,我们通常...

    cocos2d-x多线程

    在Cocos2d-x中,多线程是一个关键的概念,它能提升应用程序的性能,使得游戏运行更加流畅。多线程允许开发者同时执行多个任务,如更新游戏逻辑、渲染图形以及处理用户输入,这有助于避免程序阻塞,提高用户体验。 ...

    Cocos2d-X游戏【泰然网《跑酷》】JS到C++移植

    在Cocos2d-X中,C++代码通常使用面向对象的设计模式,例如继承自Node或Component等基类。 2. **Cocos2d-X C++ API**:熟悉并使用Cocos2d-X的C++ API至关重要。这包括精灵(Sprite)、场景(Scene)、动作(Action)...

    cocos2d-x 的几个不错的代码联合起来使用

    通过分析和学习这个横版游戏的源码,开发者可以了解到Cocos2d-x中如何创建场景(Scenes)、节点(Nodes)、精灵(Sprites)、动作(Actions)以及物理引擎的使用等。这些是构建游戏世界的基本元素,也是理解Cocos2d-...

    cocos2d-x多线程和同步

    在cocos2d-x游戏开发框架中,多线程和同步...总之,理解和掌握cocos2d-x中的多线程和同步技术对于开发高性能、低延迟的游戏至关重要。开发者需要谨慎地设计和实现多线程代码,以充分利用系统资源并提供流畅的游戏体验。

    cocos2d-x 聊天小程序1 数据的简单数据通信

    在Cocos2d-x中,我们通常会用到如cocos2d::network::HttpClient或第三方库如libcurl来实现HTTP请求,或者使用WebSocket库如libwebsockets或SimpleWebSocketServer来处理长连接通信。HTTP主要用于发送GET和POST请求,...

    cocos2d-x多线程异步加载资源

    在Cocos2d-x中,资源如图片、音频、字体等通常需要预先加载到内存中,以便在游戏中快速访问。然而,同步加载这些资源可能导致主游戏线程阻塞,从而影响游戏的流畅性。 Boost是一个流行的C++库,它包含了一系列实用...

    带有服务器端源代码 的 Cocos2d-x 多人游戏示例_C++_代码_下载

    Cocos2d-x 是一个广泛使用的开源游戏开发框架,它基于C++,并支持多平台,包括iOS、Android、Windows以及各种网页浏览器。这个“带有服务器端源代码的 Cocos2d-x 多人游戏示例”是一个专为开发者设计的资源,用于...

    cocos2d-x异步加载plist

    4. **CCFileUtils**:这是cocos2d-x中用于文件操作的基础类,提供了异步读取文件的方法。例如,`[[CCFileUtils sharedFileUtils] asyncLoadFile:filePath target:target selector:selector]` 可以异步加载文件,当...

    cocos2d-x bsd socket

    在Cocos2d-x中,我们可以利用这个标准的网络编程接口来实现这些需求。 BSD Sockets是Unix系统中的一种网络编程API,后来也被广泛移植到其他操作系统,包括Windows。它提供了一组与平台无关的接口,允许程序员创建...

    cocos2d-x操作数据库

    本篇文章将深入探讨如何在Cocos2d-x中操作SQLite数据库。 首先,我们需要了解在Cocos2d-x中集成SQLite的基本步骤。这通常涉及到以下几个关键点: 1. **引入SQLite库**:Cocos2d-x并不直接支持SQLite,因此需要手动...

    cocos2d-x学习笔记(14)--CCTextureCache .rar

    CCTextureCache是cocos2d-x中的一个单例类,它主要的作用是提供纹理的全局缓存服务。在游戏开发中,我们经常需要加载各种图像资源,如精灵、背景、按钮等,这些都依赖于纹理。通过CCTextureCache,我们可以避免重复...

    cocos2d-lua 调试插件

    在游戏开发领域,cocos2d-lua是一个广受欢迎的框架,它结合了cocos2d-x的强大性能和Lua的易用性,使得开发者能够快速构建游戏。然而,如同任何编程过程一样,调试是不可或缺的一环,为了提升开发效率,BabeLua便...

    cocos2dx多线程

    - **Cocos2d-x中的线程池**:虽然Cocos2d-x没有内置线程池,但可以通过自定义实现,例如使用`std::queue`和`std::thread`组合实现。 9. **性能优化** - **线程数量的控制**:过多的线程会导致更多的上下文切换,...

    Cocos2d-x 3.0多线程异步加载资源实例

    在移动游戏开发中,尤其是在使用Cocos2d-x游戏引擎开发时,多线程异步加载资源是优化游戏性能,提升用户体验的重要技术手段。Cocos2d-x游戏引擎是目前移动游戏开发中非常流行的一个开源框架,它支持2D游戏的开发。...

    iOS游戏应用源代码——Devint6669-cocos2d-iphone-bedca97.zip

    同时,游戏开发通常涉及到多线程编程,理解GCD(Grand Central Dispatch)或其他并发技术在游戏更新循环中的作用也很重要。 总之,通过分析和研究这个源代码,开发者不仅可以提升Cocos2D-iPhone的使用技能,也能...

    pomelo-cocos2dxchat-v3:基于libpomelo2和cocos2d-x v3.8的pomelo-cocos2dchat演示

    理解如何在cocos2d-x中使用协程或者调度器来处理异步任务。 6. **数据序列化与反序列化**:libpomelo2处理的数据通常需要进行序列化和反序列化,以便在网络上传输。掌握JSON或者其他序列化格式的使用,可以有效地将...

    cocos2dx-3.6封装的弱联网类(Http请求)

    在Cocos2d-x中,可以使用`HttpClient`类来发起异步请求。`HttpClient`会负责在网络线程中执行请求,并在主线程中回调结果。 4. **错误处理**:在封装类中,我们需要考虑各种可能出现的网络错误,如连接超时、服务器...

    线程安全的消息中心

    总结来说,Cocos2d-x 3.2中的线程安全消息中心是一个关键的组件,通过使用同步机制如互斥锁等,保证了在多线程环境下的消息传递安全可靠。`MsgManager`类的实现提供了订阅、取消订阅和发布消息的功能,这些功能在...

    elevator.rar

    《Cocos2d-x引擎下的电梯模拟调度程序详解》 在计算机科学中,电梯调度算法是一种典型的多任务处理问题,其目标...深入研究此项目,不仅可以提升C++编程和Cocos2d-x使用技能,也能加深对多线程编程和调度算法的理解。

Global site tag (gtag.js) - Google Analytics