首页 > 代码库 > 多线程以及线程同步

多线程以及线程同步

cocos2d-x引擎在内部实现了一个庞大的主循环,每帧之间更新界面,如果耗时的操作放到了主线程中,游戏的界面就会卡,这是不能容忍的,游戏最基本的条件就是流畅性,这就是为什么游戏开发选择C++的原因。另外现在双核手机和四核手机越来越普遍了,是时候使用多线程来挖掘硬件的潜力了。

1.环境搭建

cocos2d-x中的多线程使用pthread就可以实现跨平台,而且也不是很难理解。使用pthread需要先配置一下工程。右击工程----->属性----->配置属性---->链接器----->输入---->附加依赖项中添加pthreadVCE2.lib,如下图

接着添加附加包含目录,右击项目,属性----->C/C++---->常规----->附加包含目录加入pthread头文件所在的目录

这样,环境就搭建起来了。

2.多线程的使用

使用pthread来实现多线程,最重要的一个函数是

 

[cpp] view plaincopy
 
  1. PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid,//线程的标示  
  2.                             const pthread_attr_t * attr,      //创建线程的参数  
  3.                             void *(*start) (void *),          //入口函数的指针  
  4.                             void *arg);                       //传递给线程的数据  


在HelloWorldScene.h文件中

 

 

[cpp] view plaincopy
 
  1. pthread_t pidrun,pidgo;  
  2. static void* th_run(void *r);  
  3. static void* th_go(void *r);  

定义了两个函数和两个线程的标识。

 

然后自定义了一个类,用于给线程传递数据。Student类如下:

 

[cpp] view plaincopy
 
  1. #pragma once  
  2. #include <string>  
  3. class Student  
  4. {  
  5. public:  
  6.     Student(void);  
  7.     Student(std::string name,int age,std::string sex);  
  8.     ~Student(void);  
  9.   
  10.     std::string name;  
  11.     int age;  
  12.     std::string sex;  
  13.   
  14. };  


源文件如下

 

 

[cpp] view plaincopy
 
  1. #include "Student.h"  
  2. #include "cocos2d.h"  
  3.   
  4. Student::Student(void)  
  5. {  
  6. }  
  7.   
  8.   
  9. Student::~Student(void)  
  10. {  
  11.     cocos2d::CCLog("delete data");  
  12. }  
  13. Student::Student(std::string name,int age,std::string sex)  
  14. {  
  15.     this->name=name;  
  16.     this->age=age;  
  17.     this->sex=sex;  
  18. }  

在退出菜单的回调函数中启动两个线程:

 

 

[cpp] view plaincopy
 
  1. void HelloWorld::menuCloseCallback(CCObject* pSender)  
  2. {  
  3.      
  4.     Student *temp=new Student(std::string("zhycheng"),23,std::string("male"));  
  5.     pthread_mutex_init(&mutex,NULL);  
  6.     pthread_create(&pidrun,NULL,th_run,temp);//启动线程  
  7.     pthread_create(&pidgo,NULL,th_go,0);  
  8.   
  9. }  


可以看到,将Student的指针传递给了pidrun线程,那么在pidrun线程中获得Student信息如下:

 

 

[cpp] view plaincopy
 
  1.        Student *s=(Student*)(r);  
  2. CCLog("name is %s,and age is %d,sex is %s",s->name.c_str(),s->age,s->sex.c_str());  
  3. delete s;  

 

 

3.线程同步

使用了线程,必然就要考虑到线程同步,不同的线程同时访问资源的话,访问的顺序是不可预知的,会造成不可预知的结果。

 

这里使用pthread_mutex_t来实现同步,下面我来演示一下使用多线程实现卖票系统。卖票的时候,是由多个窗口同时卖票,这里要做到一张票不要卖出去两次,不要出现有票却无法卖的结果。

在线程函数th_run和th_go中来卖票,票的数量是一个全局变量,每卖出去一张票,就将票的数量减一。其中同步的pthread_mutex_t也是一个全局变量,就用它来实现线程同步。

 

[cpp] view plaincopy
 
  1. void* HelloWorld::th_run(void *r)  
  2. {  
  3.       
  4.     Student *s=(Student*)(r);  
  5.     CCLog("name is %s,and age is %d,sex is %s",s->name.c_str(),s->age,s->sex.c_str());  
  6.     delete s;  
  7.     while(true)  
  8.     {  
  9.         pthread_mutex_lock(&mutex);  
  10.         if(ticket>0)  
  11.         {  
  12.         CCLog("thread run sell %d",ticket);  
  13.         ticket--;  
  14.         pthread_mutex_unlock(&mutex);  
  15.         }  
  16.         else  
  17.         {  
  18.             pthread_mutex_unlock(&mutex);  
  19.             break;    
  20.         }  
  21.       
  22.         Sleep(1);  
  23.         //Usleep(10);  
  24.     }  
  25.   
  26.     return NULL;  
  27. }  

 

[cpp] view plaincopy
 
  1. void* HelloWorld::th_go(void *r)  
  2. {  
  3.       
  4.     while(true)  
  5.     {  
  6.         pthread_mutex_lock(&mutex);  
  7.         if(ticket>0)  
  8.         {  
  9.         CCLog("thread go sell %d",ticket);  
  10.         ticket--;  
  11.         pthread_mutex_unlock(&mutex);  
  12.         }  
  13.         else  
  14.         {  
  15.             pthread_mutex_unlock(&mutex);  
  16.             break;  
  17.               
  18.         }  
  19.           
  20.         Sleep(1);  
  21.           
  22.     }  
  23.     return NULL;  
  24. }  



 

 

mutex被锁定后,其他线程若再想锁定mutex的话,必须等待,当该线程释放了mutex之后,其他线程才能锁定mutex。Sleep()函数可以使得该线程休眠,单位是毫秒。下面是卖票的结果:

 

 

[cpp] view plaincopy
 
  1. name is zhycheng,and age is 23,sex is male  
  2. delete data  
  3. thread run sell 100  
  4. thread run sell 99  
  5. thread go sell 98  
  6. thread go sell 97  
  7. thread run sell 96  
  8. thread go sell 95  
  9. thread go sell 94  
  10. thread run sell 93  
  11. thread go sell 92  
  12. thread run sell 91  
  13. thread go sell 90  
  14. thread go sell 89  
  15. thread run sell 88  
  16. thread go sell 87  
  17. thread run sell 86  
  18. thread go sell 85  
  19. thread run sell 84  
  20. thread go sell 83  
  21. thread run sell 82  
  22. thread go sell 81  
  23. thread run sell 80  
  24. thread go sell 79  
  25. thread run sell 78  
  26. thread go sell 77  
  27. thread run sell 76  
  28. thread go sell 75  
  29. thread run sell 74  
  30. thread go sell 73  
  31. thread run sell 72  
  32. thread go sell 71  
  33. thread run sell 70  
  34. thread go sell 69  
  35. thread go sell 68  
  36. thread run sell 67  
  37. thread go sell 66  
  38. thread run sell 65  
  39. thread go sell 64  
  40. thread run sell 63  
  41. thread go sell 62  
  42. thread run sell 61  
  43. thread go sell 60  
  44. thread run sell 59  
  45. thread go sell 58  
  46. thread run sell 57  
  47. thread go sell 56  
  48. thread run sell 55  
  49. thread go sell 54  
  50. thread run sell 53  
  51. thread run sell 52  
  52. thread go sell 51  
  53. thread run sell 50  
  54. thread go sell 49  
  55. thread run sell 48  
  56. thread go sell 47  
  57. thread run sell 46  
  58. thread go sell 45  
  59. thread run sell 44  
  60. thread run sell 43  
  61. thread go sell 42  
  62. thread run sell 41  
  63. thread run sell 40  
  64. thread go sell 39  
  65. thread run sell 38  
  66. thread run sell 37  
  67. thread run sell 36  
  68. thread run sell 35  
  69. thread go sell 34  
  70. thread run sell 33  
  71. thread run sell 32  
  72. thread go sell 31  
  73. thread run sell 30  
  74. thread run sell 29  
  75. thread run sell 28  
  76. thread run sell 27  
  77. thread run sell 26  
  78. thread run sell 25  
  79. thread go sell 24  
  80. thread run sell 23  
  81. thread go sell 22  
  82. thread go sell 21  
  83. thread run sell 20  
  84. thread go sell 19  
  85. thread run sell 18  
  86. thread run sell 17  
  87. thread go sell 16  
  88. thread run sell 15  
  89. thread go sell 14  
  90. thread go sell 13  
  91. thread run sell 12  
  92. thread go sell 11  
  93. thread go sell 10  
  94. thread run sell 9  
  95. thread go sell 8  
  96. thread run sell 7  
  97. thread go sell 6  
  98. thread go sell 5  
  99. thread run sell 4  
  100. thread go sell 3  
  101. thread run sell 2  
  102. thread run sell 1  



 

 

可以看到,这个打印结果正确无误。如果不加mutex会是什么样的结果呢,我将线程同步的mutex注释掉,输出的结果为:

 

[cpp] view plaincopy
 
  1. name is zhycheng,and age is 23,sex is male  
  2. delete data  
  3. thread run sell 100  
  4. thread run sell 99  
  5. thread run sell 98  
  6. thread go sell 97  
  7. thread run sell 96  
  8. thread go sell 95  
  9. thread run sell 94  
  10. thread go sell 94  
  11. thread run sell 92  
  12. thread run sell 91  
  13. thread go sell 90  
  14. thread run sell 89  
  15. thread go sell 88  
  16. thread run sell 87  
  17. thread run sell 86  
  18. thread go sell 86  
  19. thread go sell 84  
  20. thread run sell 83  
  21. thread go sell 82  
  22. thread run sell 81  
  23. thread go sell 80  
  24. thread run sell 79  
  25. thread run sell 78  
  26. thread go sell 77  
  27. thread run sell 76  
  28. thread run sell 75  
  29. thread go sell 74  
  30. thread run sell 73  
  31. thread go sell 72  
  32. thread run sell 71  
  33. thread go sell 70  
  34. thread go sell 69  
  35. thread run sell 68  
  36. thread go sell 67  
  37. thread go sell 66  
  38. thread run sell 65  
  39. thread go sell 64  
  40. thread go sell 63  
  41. thread run sell 62  
  42. thread go sell 61  
  43. thread run sell 60  
  44. thread run sell 59  
  45. thread run sell 58  
  46. thread run sell 57  
  47. thread run sell 56  
  48. thread run sell 55  
  49. thread go sell 54  
  50. thread run sell 54  
  51. thread go sell 52  
  52. thread run sell 52  
  53. thread go sell 50  
  54. thread run sell 50  
  55. thread go sell 49  
  56. thread run sell 47  
  57. thread go sell 47  
  58. thread go sell 45  
  59. thread run sell 45  
  60. thread run sell 43thread go sell 43  
  61.   
  62. thread run sell 41  
  63. thread go sell 41  
  64. thread go sell 39  
  65. thread run sell 39  
  66. thread run sell 37  
  67. thread go sell 37  
  68. thread go sell 35  
  69. thread run sell 35  
  70. thread go sell 33thread run sell 33  
  71.   
  72. thread go sell 31thread run sell 31  
  73.   
  74. thread go sell 29  
  75. thread run sell 29  
  76. thread go sell 27  
  77. thread run sell 27  
  78. thread go sell 25  
  79. thread run sell 25  
  80. thread run sell 23  
  81. thread go sell 23  
  82. thread run sell 21  
  83. thread go sell 21  
  84. thread go sell 19  
  85. thread run sell 19  
  86. thread run sell 17  
  87. thread go sell 17  
  88. thread go sell 15  
  89. thread run sell 15  
  90. thread run sell 13  
  91. thread go sell 13  
  92. thread run sell 11thread go sell 11  
  93.   
  94. thread go sell 9  
  95. thread run sell 9  
  96. thread run sell 7  
  97. thread go sell 7  
  98. thread go sell 5thread run sell 5  
  99.   
  100. thread go sell 3  
  101. thread run sell 3  
  102. thread go sell 1  
  103. thread run sell 1  



 

可以看到,有的票卖了两次,有的票就没卖。

 

4.注意

1.Sleep()函数是使得线程休眠的函数,这个函数不跨平台,仅仅在windows上能用,其他平台使用usleep。

2.在非主线程中不能使用cocos2d-x管理内存的CCObject::retain()CCObject::release() 者CCObject::autorelease(),因为CCAutoreleasePool不是线程安全的,OPENGL的上下文也不是线程安全的,所以不要再非主线程中使用cocos2d-x的API和UI操作。

 

最后工程的源代码下载:http://download.csdn.net/detail/zhy_cheng/5600979

转自:http://blog.csdn.net/zhy_cheng/article/details/9116479

多线程以及线程同步