在手游开发过程中, 经常会用到需要异步的情况, 也就是多线程, cocos2d-x本身并没有关于线程的相关代码.但幸好ios 及 android系统都实现了Posix系统调用. 这里就利用posix手动开启线程方面,做一个总结,以备忘
先介绍一些基本的线程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,否则返回错误编号
举例:一个下载器的实例
DownLoader.h
// // DownLoader.h // MythLeague // // Created by raochongtao on 13-6-25. // // /* * 1.开线程 * 2.下载分配给自己的资源 * 3.监听自己是否下载完 * 4.和管理器交互 */ #ifndef __MythLeague__DownLoader__ #define __MythLeague__DownLoader__ #include "Global/Constants.h" typedef enum{ DownloadStatus_Init, DownloadStatus_Loading, DownloadStatus_Success, DownloadStatus_FailedWhen_Init, DownloadStatus_FailedWhen_GetHandle, DownloadStatus_FailedWhen_GetInfo, }Enum_DownloadStatus; class DownLoader : public cocos2d::CCObject{ public: DownLoader(); virtual ~DownLoader(); CREATE_FUNC(DownLoader); bool init(); //下载资源 void downloadRes(Struct_DownLoadTask p_downloadTask); //开线程 static void* startNewThread(void* args); bool startDownload(); //处理下载数据 static size_t process_data(void *buffer, size_t size, size_t nmemb, std::string& user_p); //监测下载完毕 void checkDownloadStatus(float p_delay); public: Struct_DownLoadTask m_downloadTask; Enum_DownloadStatus m_iDownloadStatus; }; #endif /* defined(__MythLeague__DownLoader__) */
DownLoader.cpp
// // DownLoader.cpp // MythLeague // // Created by raochongtao on 13-6-25. // // #include "DownLoader.h" #include "DownloadMgr.h" #include "Global/Tools.h" #define FILE_EXIST (200) #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #include "CURL/curl.h" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) #include "platform/third_party/win32/curl/curl.h" #elif (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "platform/third_party/android/modules/libcurl/include/curl/curl.h" #endif using namespace std; using namespace cocos2d; #define DownLoader_Check_Interval (0.5f) DownLoader::DownLoader(){ m_iDownloadStatus = DownloadStatus_Init; } DownLoader::~DownLoader(){ } bool DownLoader::init(){ return true; } //下载资源 void DownLoader::downloadRes(Struct_DownLoadTask p_downloadTask){ m_downloadTask = p_downloadTask; pthread_t l_pid; pthread_attr_t l_attr; pthread_attr_init(&l_attr); int l_iPriority = sched_get_priority_max(SCHED_OTHER); pthread_attr_setschedpolicy(&l_attr, l_iPriority); pthread_create(&l_pid, &l_attr, DownLoader::startNewThread, this); CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(DownLoader::checkDownloadStatus), this, DownLoader_Check_Interval, false); } //开线程(静态方法) void* DownLoader::startNewThread(void* p_args){ //线程独立 pthread_detach(pthread_self()); //自己新线程里下载 DownLoader* l_thisDownloader = (DownLoader*)p_args; l_thisDownloader->startDownload(); return NULL; } bool DownLoader::startDownload(){ m_iDownloadStatus = DownloadStatus_Loading; #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) // 初始化libcurl CURLcode return_code; return_code = curl_global_init(CURL_GLOBAL_ALL); if (CURLE_OK != return_code) { CCLog("init libcurl failed."); curl_global_cleanup(); m_iDownloadStatus = DownloadStatus_FailedWhen_Init; return false; } // 获取easy handle CURL *easy_handle = curl_easy_init(); if (NULL == easy_handle) { CCLog("get a easy handle failed."); curl_easy_cleanup(easy_handle); curl_global_cleanup(); m_iDownloadStatus = DownloadStatus_FailedWhen_GetHandle; return false; } // 设置easy handle属性 return_code = curl_easy_setopt(easy_handle, CURLOPT_URL, m_downloadTask.resUrl.c_str()); //设置回调函数 //return_code = curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, &process_data); curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, process_data); //回调函数的额外参数 std::string connectx; return_code = curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &connectx); // 执行数据请求 return_code = curl_easy_perform(easy_handle); //判断获取响应的http地址是否存在,若存在则返回200,400以上则为不存在,一般不存在为404错误 int retcode = 0; return_code = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE , &retcode); if (CURLE_OK == return_code && FILE_EXIST == retcode) { double length = 0; return_code = curl_easy_getinfo(easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD , &length); string l_fullPath = Tools::getWritableFilePath(m_downloadTask.fileName.c_str()); FILE *fp = fopen(l_fullPath.c_str(), "wb+"); if(fp != NULL){ fwrite(connectx.c_str(), 1, length, fp); //返回实际写入文本的长度,若不等于length则写文件发生错误. fclose(fp); }else{ CCLog("error here file: %s line: %d", __FILE__, __LINE__); } } else { CCLog("......url文件不存在!"); curl_easy_cleanup(easy_handle); curl_global_cleanup(); m_iDownloadStatus = DownloadStatus_FailedWhen_GetInfo; return false; } // 释放资源 curl_easy_cleanup(easy_handle); curl_global_cleanup(); #endif m_iDownloadStatus = DownloadStatus_Success; return 0; } //处理下载数据 size_t DownLoader::process_data(void *buffer, size_t size, size_t nmemb, std::string& user_p){ user_p.append((char*)buffer, size*nmemb); return size*nmemb; } //监测下载完毕 void DownLoader::checkDownloadStatus(float p_delay){ if (m_iDownloadStatus >= DownloadStatus_Success) { CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(DownLoader::checkDownloadStatus), this); //成功回调 if (m_iDownloadStatus == DownloadStatus_Success) { DownloadMgr::sharedMgr()->callWhenDownloaderFinish_success(this); } //失败回调 else{ DownloadMgr::sharedMgr()->callWhenDownloaderFinish_failed(this); } } }
这样实现了,一个下载器的基本功能,但在处理异常方面还有待完善。
其它需要做的还有,需要写一个下载管理器,管理器的基本功能要包括:
/*
* 1.管理下载器,一个或多个
* 2.显示DownLoading及进度
* 并屏蔽事件
* 3.与外部交互的接口
*/
另外,还需要一个用于显示下载内容及下载进度的显示层。
这两个层,会陆续传上来。