cocos2dx-TextureCache::addImageAsync函数详解
来源:互联网 发布:如何快速提高淘宝等级 编辑:程序博客网 时间:2024/06/06 02:15
这几天使用了cocos2dx后,对异步加载很感兴趣,所谓过异步加载,就是开启多线程进行资源的加载,同时因为cocos2dx的PoolManager(内存池)不是线程安全的,所以在工作线程中就得避免使用release() retain() autorelease()等函数。
因为现在的cocos2dx已经是3.x时代了,好些内容已经进行了改变,就比如异步加载资源,cocos2dx在 2.x使用的是pthread,是线程的POSIX标准。而在3.x就全部使用了c++11标准的<thread> <mutex>等标准库
先看看代码吧
void TextureCache::addImageAsync(const std::string &path, const std::function<void(Texture2D*)>& callback){ Texture2D *texture = nullptr; //根据当前路径获取绝对路径 std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path); //当前是否存在该绝对路径所对应的texture auto it = _textures.find(fullpath); if( it != _textures.end() ) texture = it->second; //如果存在,则尝试直接回调该函数 if (texture != nullptr) { if (callback) callback(texture); return; } // 检测文件是否真的存在,如果不存在,尝试回调函数 if ( fullpath.empty() || ! FileUtils::getInstance()->isFileExist( fullpath ) ) { if (callback) callback(nullptr); return; } /*滞后赋值 创建一个工作线程,是c++11新增的,相对比较大的优点就是可以传递类的成员函数,第二个参数传递对象的指针*/ if (_loadingThread == nullptr) { // 创建一个新的线程来不停尝试加载图片资源 _loadingThread = new std::thread(&TextureCache::loadImage, this); _needQuit = false; } //开始定时调度器,会在主线程中一直尝试作加载资源的收尾阶段,比如创建Texture2D,回调函数等 if (0 == _asyncRefCount) { Director::getInstance()->getScheduler()->schedule(CC_SCHEDULE_SELECTOR(TextureCache::addImageAsyncCallBack), this, 0, false); } //引用计数器加一 ++_asyncRefCount; // 创建异步加载结构体,这个结构体内保存着资源路径,回调函数,异步加载完成的Image,以及loadSuccess,表示是否加载成功 AsyncStruct *data = new (std::nothrow) AsyncStruct(fullpath, callback); // 增加这个异步结构体到队列中 _asyncStructQueue.push_back(data); //std::mutex 互斥体,避免多线程同时访问 _requestMutex.lock(); _requestQueue.push_back(data); _requestMutex.unlock(); //唤醒等待进程 _sleepCondition.notify_one();}
cocos2dx很巧妙地实现了异步加载。即cocos2dx维护了
_requestQueue 请求加载队列 由addImageAsync添加 在loadImage中进行移除
_responseQueue 加载完成队列 资源在loadImage中加载完成后,就会添加到此队列中 然后在addImageAsyncCallback函数中进行一些收尾工作
void TextureCache::loadImage(){ AsyncStruct *asyncStruct = nullptr; std::mutex signalMutex; std::unique_lock<std::mutex> signal(signalMutex); while (!_needQuit) { // 从请求队列中移除一个加载结构体 _requestMutex.lock(); if(_requestQueue.empty()) { asyncStruct = nullptr; }else { asyncStruct = _requestQueue.front(); _requestQueue.pop_front(); } _requestMutex.unlock(); //当前请求队列已经全部加载完毕,此线程阻塞直至被唤醒,这个在addImageAsync中会被唤醒 if (nullptr == asyncStruct) { _sleepCondition.wait(signal); continue; } // 加载image asyncStruct->loadSuccess = asyncStruct->image.initWithImageFileThreadSafe(asyncStruct->filename); // 把加载完成的结构体放在加载完成队列中 _responseMutex.lock(); _responseQueue.push_back(asyncStruct); _responseMutex.unlock(); }}这个函数主要负责异步加载资源,至于那个条件变量_sleepCondition,在http://blog.csdn.net/watson2016/article/details/52861094中这样说到,"当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。"
void TextureCache::addImageAsyncCallBack(float dt){ Texture2D *texture = nullptr; AsyncStruct *asyncStruct = nullptr; while (true) { // 从加载完成队列中移除一个结构体指针 _responseMutex.lock(); if(_responseQueue.empty()) { asyncStruct = nullptr; }else { asyncStruct = _responseQueue.front(); _responseQueue.pop_front(); // 必须保证资源是按序加载 CC_ASSERT(asyncStruct == _asyncStructQueue.front()); _asyncStructQueue.pop_front(); } _responseMutex.unlock(); //当前加载完成队列为空,直接退出这次循环 if (nullptr == asyncStruct) { break; } // 再次进行一个检测 auto it = _textures.find(asyncStruct->filename); if(it != _textures.end()) { texture = it->second; } else { // 转换成Texture2D if (asyncStruct->loadSuccess) { Image* image = &(asyncStruct->image); // generate texture in render thread texture = new (std::nothrow) Texture2D(); texture->initWithImage(image); //parse 9-patch info //...略 } // 尝试回调函数 if (asyncStruct->callback) { (asyncStruct->callback)(texture); } // 释放资源 delete asyncStruct; --_asyncRefCount; } //当前没有请求加载的资源,取消这个函数的调用 if (0 == _asyncRefCount) { Director::getInstance()->getScheduler()->unschedule(CC_SCHEDULE_SELECTOR(TextureCache::addImageAsyncCallBack), this); }}如果加载完成队列非空,则一次性进行资源加载的后续处理。
使用异步加载也会对帧率造成影响,因为在addImageAsync内部需要获取互斥体_requestMutex,如果此时工作线程正好拥有此互斥体的话,主线程就会堵塞,直到获取到,不过这一点时间相对于主线程加载图片的时间就小巫见大巫了
0 0
- cocos2dx-TextureCache::addImageAsync函数详解
- cocos2d-x TextureCache::addImageAsync 方法的陷阱
- 纹理缓存TextureCache-Cocos2dx
- cocos2dx-3.0(33) 中的缓存TextureCache、SPriteFrameCache、AnimationCache
- cocos2dx-3.0(33) 中的缓存TextureCache、SPriteFrameCache、AnimationCache
- cocos2dx-3.0(33) 中的缓存TextureCache、SPriteFrameCache、AnimationCache
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx中lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解
- cocos2dx+lua注册事件函数详解 事件
- TextureCache SpriteFrameCache
- cocos2dx 常见的49中动作详解及常用函数
- cocos2dx+lua 3.1.1 注册事件函数详解
- c语言编程题目
- 在pycharm中调用用caffe的python接口时,import caffe失败的解决办法
- (3)Linux修改主机名和建立IP和hostname映射
- sqlite3创建数据仓库xxx.db(为何我创建sqlite仓库却没有生成文件)
- wpf KeyDown 无法捕获 Backspace space
- cocos2dx-TextureCache::addImageAsync函数详解
- properties工具类
- Hibernate mapping resource 详解
- C#.NET实现基于Lumisoft的邮件收发功能
- php的array_multisort()数组使用总结
- springBoot配置devtools实现热部署
- DNS原理及其解析过程【精彩剖析】
- matlab提示"Message Catalog MATLAB:FileIO was not loaded from the file. Please check file location, "
- 树状数组专题