cocos2dx HttpRequest引用计数理解

来源:互联网 发布:李逵打鱼版本源码 编辑:程序博客网 时间:2024/06/15 13:02
        HttpRequest* request = new (std::nothrow) HttpRequest();        request->setUrl("http://httpbin.org/post");        request->setRequestType(HttpRequest::Type::POST);        std::vector<std::string> headers;        headers.push_back("Content-Type: application/json; charset=utf-8");        request->setHeaders(headers);        request->setResponseCallback(CC_CALLBACK_2(HttpClientTest::onHttpRequestCompleted, this));                // write the post data        const char* postData = "visitor=cocos2d&TestSuite=Extensions Test/NetworkTest";        request->setRequestData(postData, strlen(postData));        if (isImmediate)        {            request->setTag("POST immediate test2");            HttpClient::getInstance()->sendImmediate(request);        }else        {            request->setTag("POST test2");            HttpClient::getInstance()->send(request);        }        request->release();

new出来是1


send后是2,其次还有_requestQueue是一个大Vector pushBack加1 是3

void HttpClient::send(HttpRequest* request){        if (false == lazyInitThreadSemphore())     {        return;    }        if (!request)    {        return;    }            request->retain();_requestQueueMutex.lock();_requestQueue.pushBack(request);_requestQueueMutex.unlock();// Notify thread start to work_sleepCondition.notify_one();}

网络线程处理一个个请求,在网络线程中,取出一个后,request = _requestQueue.at(0); 移除一个,再次变为2

void HttpClient::networkThread(){   increaseThreadCount();        while (true)     {        HttpRequest *request;        // step 1: send http request if the requestQueue isn't empty        {            std::lock_guard<std::mutex> lock(_requestQueueMutex);            while (_requestQueue.empty()){                _sleepCondition.wait(_requestQueueMutex);            }            request = _requestQueue.at(0);            _requestQueue.erase(0);        }        if (request == _requestSentinel) {            break;        }        // step 2: libcurl sync access                // Create a HttpResponse object, the default setting is http access failed        HttpResponse *response = new (std::nothrow) HttpResponse(request);        processResponse(response, _responseMessage);                // add response packet into queue        _responseQueueMutex.lock();        _responseQueue.pushBack(response);        _responseQueueMutex.unlock();        _schedulerMutex.lock();if (nullptr != _scheduler){_scheduler->performFunctionInCocosThread(CC_CALLBACK_0(HttpClient::dispatchResponseCallbacks, this));}_schedulerMutex.unlock();    }        // cleanup: if worker thread received quit signal, clean up un-completed request queue    _requestQueueMutex.lock();    _requestQueue.clear();    _requestQueueMutex.unlock();    _responseQueueMutex.lock();_responseQueue.clear();_responseQueueMutex.unlock();decreaseThreadCountAndMayDeleteThis();    }


内部调用curl库处理应该返回给客户端的响应

// Process Responsevoid HttpClient::processResponse(HttpResponse* response, char* responseMessage){auto request = response->getHttpRequest();long responseCode = -1;int retValue = 0;// Process the request -> get response packetswitch (request->getRequestType()){case HttpRequest::Type::GET: // HTTP GETretValue = processGetTask(this, request,writeData,response->getResponseData(),&responseCode,writeHeaderData,response->getResponseHeader(),responseMessage);break;case HttpRequest::Type::POST: // HTTP POSTretValue = processPostTask(this, request,writeData,response->getResponseData(),&responseCode,writeHeaderData,response->getResponseHeader(),responseMessage);break;case HttpRequest::Type::PUT:retValue = processPutTask(this, request,writeData,response->getResponseData(),&responseCode,writeHeaderData,response->getResponseHeader(),responseMessage);break;case HttpRequest::Type::DELETE:retValue = processDeleteTask(this, request,writeData,response->getResponseData(),&responseCode,writeHeaderData,response->getResponseHeader(),responseMessage);break;default:CCASSERT(true, "CCHttpClient: unknown request type, only GET and POSt are supported");break;}// write data to HttpResponseresponse->setResponseCode(responseCode);if (retValue != 0){response->setSucceed(false);response->setErrorBuffer(responseMessage);}else{response->setSucceed(true);}}


调用curl库,等待获取结果
//Process Get Requeststatic int processGetTask(HttpClient* client, HttpRequest* request, write_callback callback, void* stream, long* responseCode, write_callback headerCallback, void* headerStream, char* errorBuffer){    CURLRaii curl;bool ok = curl.init(client, request, callback, stream, headerCallback, headerStream, errorBuffer)            && curl.setOption(CURLOPT_FOLLOWLOCATION, true)            && curl.perform(responseCode);    return ok ? 0 : 1;}



获取结果后,在这里调用注册的回调函数。当分发完消息后,再次release,引用基数减1,变为1

void HttpClient::dispatchResponseCallbacks(){    // log("CCHttpClient::dispatchResponseCallbacks is running");    //occurs when cocos thread fires but the network thread has already quited    HttpResponse* response = nullptr;    _responseQueueMutex.lock();    if (!_responseQueue.empty())    {        response = _responseQueue.at(0);        _responseQueue.erase(0);    }    _responseQueueMutex.unlock();        if (response)    {        HttpRequest *request = response->getHttpRequest();        const ccHttpRequestCallback& callback = request->getCallback();        Ref* pTarget = request->getTarget();        SEL_HttpResponse pSelector = request->getSelector();        if (callback != nullptr)        {            callback(this, response);        }        else if (pTarget && pSelector)        {            (pTarget->*pSelector)(this, response);        }                response->release();        // do not release in other thread        request->release();    }}

注意最后的,网络线程退出while循环时,调用clear函数。

 void clear()

    {

        for( auto it =std::begin(_data); it !=std::end(_data); ++it ) {

            (*it)->release();

        }

        _data.clear();

    }


最终里面的搜游数据引用计数因为变为0,所有内存被释放。




一个有意思的地方是:

if (request == _requestSentinel) {            break;        }

退出while循环的条件是这个

void HttpClient::decreaseThreadCountAndMayDeleteThis(){bool needDeleteThis = false;_threadCountMutex.lock();--_threadCount;if (0 == _threadCount){needDeleteThis = true;}_threadCountMutex.unlock();if (needDeleteThis){delete this;}}
_requestSentinel(new HttpRequest())

void HttpClient::destroyInstance(){if (nullptr == _httpClient){CCLOG("HttpClient singleton is nullptr");return;}CCLOG("HttpClient::destroyInstance begin");auto thiz = _httpClient;_httpClient = nullptr;thiz->_scheduler->unscheduleAllForTarget(thiz);thiz->_schedulerMutex.lock();thiz->_scheduler = nullptr;thiz->_schedulerMutex.unlock();thiz->_requestQueueMutex.lock();thiz->_requestQueue.pushBack(thiz->_requestSentinel);thiz->_requestQueueMutex.unlock();thiz->_sleepCondition.notify_one();thiz->decreaseThreadCountAndMayDeleteThis();CCLOG("HttpClient::destroyInstance() finished!");}

这样,当消除单利的时候,将卫梢放进去,这样当检测出来是卫梢时,就退出网络线程。










0 0
原创粉丝点击