今天我们要学习的就是cocos2d-x 多线程编程,对这方面还有不了解或者感兴趣的同学可以看一下。

先介绍一些基本的线程api

就像每个进程有一个进程ID一样,每个线程也有一个线程ID,进程ID在整个系统中是唯一的,但线程不同,线程ID只在它所属的进程环境中有效。线程ID用pthread_t数据类型来表示,实现的时候可以用一个结构来代表pthread_t数据类型,所以可以移植的操作系统不能把它作为整数处理。因此必须使用函数来对来对两个线程ID进行比较。

1.名称:pthread_equal
功能:比较两个线程ID
头文件:#include <pthread.h>
函数原形:int pthread_equal(pthread_t tid1,pthread_t tid2);
参数:tid1 进程1id, tid2 进程2id

返回值:若相等返回非0值,否则返回0

2.名称:pthread_self
功能:获取自身线程的id
头文件:#include <pthread.h>
函数原形:pthread_t pthread_self(void);
参数:无

返回值:调用线程的线程id

线程的创建

3.名称:pthread_create
功能:创建线程
头文件:#include <pthread.h>
函数原形:int pthread_create(pthread_t *restrict tidp,const pthread _attr_t *restrict attr,void *(*start_rtn)(void),void *restrict arg);
参数:
返回值:若成功返回则返回0,否则返回错误编号
举例:一个下载器的实例
  1. DownLoader.h
  2. //
  3. //  DownLoader.h
  4. //  MythLeague
  5. //
  6. //
  7. //
  8. /*
  9. * 1.开线程
  10. * 2.下载分配给自己的资源
  11. * 3.监听自己是否下载完
  12. * 4.和管理器交互
  13. */
  14. #ifndef __MythLeague__DownLoader__
  15. #define __MythLeague__DownLoader__
  16. #include "Global/Constants.h"
  17. typedef enum{
  18. DownloadStatus_Init,
  19. DownloadStatus_Loading,
  20. DownloadStatus_Success,
  21. DownloadStatus_FailedWhen_Init,
  22. DownloadStatus_FailedWhen_GetHandle,
  23. DownloadStatus_FailedWhen_GetInfo,
  24. }Enum_DownloadStatus;
  25. // 下载任务
  26. typedef struct {
  27. std :: string resUrl;
  28. std :: string fileName;
  29. }Struct_DownLoadTask;
  30. class DownLoader : public cocos2d::CCObject{ public: DownLoader();
  31.  virtual ~DownLoader();
  32.  CREATE_FUNC(DownLoader); 
  33. bool init(); //下载资源
  34.  void downloadRes(Struct_DownLoadTask p_downloadTask); //开线程 
  35. static void* startNewThread(void* args);
  36.  bool startDownload(); //处理下载数据 
  37. static size_t process_data(void *buffer, size_t size, size_t nmemb, std::string& user_p); //监测下载完毕
  38. void checkDownloadStatus(float p_delay); 
  39. public: Struct_DownLoadTask m_downloadTask; Enum_DownloadStatus m_iDownloadStatus; };
  40.  #endif /* defined(__MythLeague__DownLoader__) */
  41. #include "DownLoader.h"
  42. #include "DownloadMgr.h"
  43. #include "Global/Tools.h"
  44. #define FILE_EXIST (200)
  45. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  46. #include "CURL/curl.h"
  47. #elif (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
  48. #include "platform/third_party/win32/curl/curl.h"
  49. #elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
  50. #include "platform/third_party/android/modules/libcurl/include/curl/curl.h"
  51. #endif
  52. using namespace std;
  53. using namespace cocos2d;
  54. #define DownLoader_Check_Interval (0.5f)
  55. DownLoader::DownLoader(){
  56. m_iDownloadStatus = DownloadStatus_Init;
  57. }
  58. DownLoader::~DownLoader(){
  59. }
  60. bool DownLoader::init(){
  61. return true;
  62. }
  63. //下载资源
  64. void DownLoader::downloadRes(Struct_DownLoadTask p_downloadTask){
  65. m_downloadTask = p_downloadTask;
  66. pthread_t l_pid;
  67. pthread_attr_t l_attr;
  68. pthread_attr_init(&l_attr);
  69. int l_iPriority = sched_get_priority_max(SCHED_OTHER);
  70. pthread_attr_setschedpolicy(&l_attr, l_iPriority);
  71. pthread_create(&l_pid, &l_attr, DownLoader::startNewThread, this);
  72. CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(DownLoader::checkDownloadStatus), this, DownLoader_Check_Interval, false);
  73. }
  74. //开线程(静态方法)
  75. void* DownLoader::startNewThread(void* p_args){
  76. //线程独立
  77. pthread_detach(pthread_self());
  78. //自己新线程里下载
  79. DownLoader* l_thisDownloader = (DownLoader*)p_args;
  80. l_thisDownloader->startDownload();
  81. return NULL;
  82. }
  83. bool DownLoader::startDownload(){
  84. m_iDownloadStatus = DownloadStatus_Loading;
  85. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
  86. // 初始化libcurl
  87. CURLcode return_code;
  88. return_code = curl_global_init(CURL_GLOBAL_ALL);
  89. if (CURLE_OK != return_code)
  90. {
  91. CCLog("init libcurl failed.");
  92. curl_global_cleanup();
  93. m_iDownloadStatus = DownloadStatus_FailedWhen_Init;
  94. return false;
  95. }
  96. // 获取easy handle
  97. CURL *easy_handle = curl_easy_init();
  98. if (NULL == easy_handle)
  99. {
  100. CCLog("get a easy handle failed.");
  101. curl_easy_cleanup(easy_handle);
  102. curl_global_cleanup();
  103. m_iDownloadStatus = DownloadStatus_FailedWhen_GetHandle;
  104. return false;
  105. }
  106. // 设置easy handle属性
  107. return_code = curl_easy_setopt(easy_handle, CURLOPT_URL, m_downloadTask.resUrl.c_str());
  108. //设置回调函数
  109. //return_code = curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, &process_data);
  110. curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, process_data);
  111. //回调函数的额外参数
  112. std::string connectx;
  113. return_code = curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &connectx);
  114. // 执行数据请求
  115. return_code = curl_easy_perform(easy_handle);
  116. //判断获取响应的http地址是否存在,若存在则返回200,400以上则为不存在,一般不存在为404错误
  117. int retcode = 0;
  118. return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE , &retcode);
  119. if (CURLE_OK == return_code && FILE_EXIST == retcode)
  120. {
  121. double length = 0;
  122. return_code = curl_easy_getinfo(easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD , &length);
  123. string l_fullPath = Tools::getWritableFilePath(m_downloadTask.fileName.c_str());
  124. FILE *fp = fopen(l_fullPath.c_str(), "wb+");
  125. if(fp != NULL){
  126. fwrite(connectx.c_str(), 1, length, fp);//返回实际写入文本的长度,若不等于length则写文件发生错误.
  127. fclose(fp);
  128. }else{
  129. CCLog("error here file: %s line: %d", __FILE__, __LINE__);
  130. }
  131. }
  132. else
  133. {
  134. CCLog("......url文件不存在!");
  135. curl_easy_cleanup(easy_handle);
  136. curl_global_cleanup();
  137. m_iDownloadStatus = DownloadStatus_FailedWhen_GetInfo;
  138. return false;
  139. }
  140. // 释放资源
  141. curl_easy_cleanup(easy_handle);
  142. curl_global_cleanup();
  143. #endif
  144. m_iDownloadStatus = DownloadStatus_Success;
  145. return 0;
  146. }
  147. //处理下载数据
  148. size_t DownLoader::process_data(void *buffer, size_t size, size_t nmemb, std::string& user_p){
  149. user_p.append((char*)buffer, size*nmemb);
  150. return size*nmemb;
  151. }
  152. //监测下载完毕
  153. void DownLoader::checkDownloadStatus(float p_delay){
  154. if (m_iDownloadStatus >= DownloadStatus_Success) {
  155. CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(DownLoader::checkDownloadStatus), this);
  156. //成功回调
  157. if (m_iDownloadStatus == DownloadStatus_Success) {
  158. DownloadMgr::sharedMgr()->callWhenDownloaderFinish_success(this);
  159. }
  160. //失败回调
  161. else{
  162. DownloadMgr::sharedMgr()->callWhenDownloaderFinish_failed(this);
  163. }
  164. }
  165. }
这样实现了,一个下载器的基本功能,但在处理异常方面还有待完善。
其它需要做的还有,需要写一个下载管理器,管理器的基本功能要包括

/*
* 1. 管理下载器 , 一个或多个
* 2. 显示 DownLoading 及进度
*   并屏蔽事件
* 3. 与外部交互的接口
*/

还需要一个显示层,用来显示当前下载内容,和总得下载进度。