多线程std::thread的使用 以及performFunctionInCocosThread函数

来源:互联网 发布:网络作家船长写的小说 编辑:程序博客网 时间:2024/06/06 02:54

原帖地址: 

[cocos2dx 3.0 (二)] 多线程std::thread的使用 以及performFunctionInCocosThread函数





有的时候很多操作如果在cocos2dx的主线程中来调用,可能会极大地占用主线程的时间,从而使游戏的不流畅。比如在获取网络文件数据或者在数据比较大的游戏存档时,就需要使用多线程了。

网上的一些教程上是使用pthread来创建新线程的,需要加入lib和头文件,但在cocos2dx 3.0中并未发现有pthread的支持文件,后来才发现在c++11中已经拥有了一个更好用的用于线程操作的类std::thread。cocos2dx 3.0的版本默认是在vs2012版本,支持c++11的新特性,使用std::thread来创建线程简直方便。

1.   std::thread的一些使用方法。

需要加头文件 #include<thread>

直接调用函数

[plain] view plaincopy
  1. std::thread t(func);   

带参数的函数
[plain] view plaincopy
  1. std::thread t(func,param1,param2...);   
类的成员函数(函数类型不需要是静态的)
[plain] view plaincopy
  1. class MyClass  
  2. {  
  3.     void func1();  
  4.     void func2(int a,string b);  
  5. }  
  6. MyClass myclass;  
  7. std::thread t1(&MyClass::func1,&myclass);   
  8. std::thread t2(&MyClass::func2,&myclass,444,"this is a string");   
  9. t1.detach();  
  10. t2.join();  

detach() 将子线程从主线程里分离,子线程执行完成后会自己释放掉资源。分离后的线程,主线程将对它将没有控制权。
join() 等待子线程执行完之后,主线程才可以继续执行下去,此时主线程会释放掉执行完后的子线程资源。

可以看出使用std::thread来创建线程十分的方便,而且可读性更好了,特别是在传参数这方面。

还有就是线程的互斥量std::mutex

[plain] view plaincopy
  1. std::mutex _mutex;  
  2. void thread_fun1()  
  3. {  
  4.    _mutex.lock();//加锁  
  5.    ...  
  6.    _mutex.unlock();//解锁  
  7. }  
  8. void thread_fun2()  
  9. {  
  10.     std::lock_guard<std::mutex> lk(_mutex); //线程开始加锁,退出时自动解锁  
  11.     ...  
  12. }  
具体的互斥量使用好有很多,但太繁了(其实是看不懂),我只写点我用的到的。
参考:

1.std::thread 学习初步

2.C++11 thread


2.performFunctionInCocosThread()

在cocos2dx中使用多线程,难免要考虑线程安全的问题。cocos2dx 3.0中新加入了一个专门处理线程安全的函数performFunctionInCocosThread()。他是Scheduler类的一个成员函数:

[plain] view plaincopy
  1. void Scheduler::performFunctionInCocosThread(const std::function<void ()> &function)  
  2.   
  3. /** calls a function on the cocos2d thread. Useful when you need to call a cocos2d function from another thread.  
  4. This function is thread safe.  
  5. @since v3.0  
  6. */  
在其他线程中控制主线程去调用一个函数,这个函数会是线程安全的。

具体定义:

[plain] view plaincopy
  1. void Scheduler::performFunctionInCocosThread(const std::function<void ()> &function)  
  2. {  
  3.     _performMutex.lock();  
  4.   
  5.     _functionsToPerform.push_back(function);  
  6.   
  7.     _performMutex.unlock();  
  8. }  

使用这个函数就能安全的在其他线程中去控制cocos2dx的一些操作了。但是在使用时也要注意一些问题:

1.同步问题 

因为使用performFunctionInCocosThread将参数函数中的代码放到主线程中去运行,所以就无法知道运行完这段代码需要多少时间,可能线程已经运行完毕退出了而那部分代码还没有执行完毕。

可以做一下测试:

[cpp] view plaincopy
  1. void thread_fun()  
  2. {  
  3.     log("new thread create:t_id:0x%x",GetCurrentThreadId());  
  4.   
  5.     Director::getInstance()->getScheduler()->performFunctionInCocosThread([&,this]  
  6.     {  
  7.         for(int i=0;i<=1000;i++){}  
  8.         log("[performFunctionInCocosThread] finished!");  
  9.     });  
  10.   
  11.     log("thread finished:t_id:0x%x",GetCurrentThreadId());  
  12. }  

然后在cocos2dx中以这个函数创建一个线程,运行可以看到结果:


可以看出performFunctionInCocosThread中的代码执行完毕在线程退出之后,所以在使用时可能要加入一些值判断代码是否已经运行完毕。

2.互斥问题

如果在线程中要使用互斥,而又要使用performFunctionInCocosThread的话。我认为应该将performFunctionInCocosThread调用放到线程的最后,然后在performFunctionInCocosThread调用函数的末尾使用mutex.unlock(),这样才能确保互斥。


在自己的线程中对精灵的创建等操作可能会没有用,所有performFunctionInCocosThread还是很有用的。

cocos2dx的线程学习就到这了吐舌头

0 0