cocos2d-x 多線程編程 Posix通用

在手遊開發過程中, 經常會用到需要異步的情況, 也就是多線程, 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.與外部交互的接口

 */

另外,還需要一個用於顯示下載內容及下載進度的顯示層。

這兩個層,會陸續傳上來。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章