void threadFunc1(){
std::cout <<
"threadFunc1:\t"
<< std::endl;
// sleep 1 秒
std::this_thread::sleep_for(std::chrono:: seconds(1));
}
std::thread thread1(&threadFunc1);
至此我们已经创建了一个线程thread1,可以对线程进行相应的join,detach等操作。
3.X版本的cocos2d-x使用std::thread创建的线程来进行资源的加载,cocos使用
TextureCache
来对纹理资源进行统一管理,在2.X版本中其是一个单件,用户可以直接在脚本层调用getInstance方法来获得对TextureCache的引用,而在3.X版本中,TextureCache由Director来进行管理。TextureCache提供了两个接口(这里只讨论这两个接口):
Texture2D
* addImage(
const
std::
string
&filepath);
virtual
void
addImageAsync(
const
std::
string
&filepath,
const
std::
function
<
void
(
Texture2D
*)>& callback);
顾名思义,第一个函数提供了直接加载纹理资源的方法,查看cocos2d-x的源码发现,该方法首先在TextureCache的缓存中查找相应的纹理资源,如果未找到则直接从磁盘中读取文件,并加入到相应缓存中。而第二个函数则是其对应的异步操作方法,该方法相对复杂,下面我们来重点看该方法的实现机制。
std::
function也是在C++11引入一种通用多态函数封装器(
general-purpose polymorphic function wrapper
)猛戳,addImageAsync的最后一个参数是当纹理资源加载完成时对调用该回调函数。
下面给出资源加载的流程图,其中忽略了loadImage线程的创建及定时器的启动销毁过程:
从流程图及源代码中可看出addImageAsync接口首先去查询缓存,如果命中则直接使用callback来处理结果,否则将要请求的资源添加到一个请求队列
_asyncStructQueue,并使用
notify_one()通知加载线程进行相应的加载操作,TextureCache使用了Lazy的方法来创建线程(线程函数loadImage),即实例化TextureCache时并不创建线程,而是等到需要异步加载时如果线程还未创建则创建一个线程。
TextureCache
::loadImage()是TextureCache的线程函数,内部运行了一个while(true)循环,当请求队列不为空时则取出队列头进行处理,该线程使用
initWithImageFileThreadSafe来从磁盘中读取数据并创建一个texture,最后将加载好的texture放入另一个队列
_imageInfoQueue中。相反如果队列为空,则使用wait方法进行等待。
addImageAsync方法中启动了一个定时器:
Director
::getInstance()->getScheduler()->schedule(
schedule_selector
(
TextureCache
::addImageAsyncCallBack),
this
, 0,
false
);, 该定时器会在每帧去检查_imageInfoQueue,如果该队列不为空,则在该帧中对_imageInfoQueue中的每个元素调用callback方法来进行渲染,当
_asyncRefCount == 0时,也即所有需要加载的纹理都已加载完成,则将该定时器清除。