• [转]OGRE多线程的使用


    上次说了多线程管理的设计方案,这里再整理下OGRE中多线程的使用方法,由于新的WorkQueue设计是通用型的,因此对于我们来说,只需要使用好这个结构即可方便地实现多线程功能。

    1、继承WorkQueue::RequestHandler、WorkQueue::ResponseHandler,准备一个uint16 mWorkQueueChannel,在类的构造函数中通过以下代码初始化:

    WorkQueue* wq = Root::getSingleton().getWorkQueue();
    mWorkQueueChannel = wq->getChannel("Ogre/Terrain"); // 这个名字自己取好
    wq->addRequestHandler(mWorkQueueChannel, this);
    wq->addResponseHandler(mWorkQueueChannel, this);

    析构时移除:

    waitForDerivedProcesses();     // 这个最后说明

    WorkQueue* wq = Root::getSingleton().getWorkQueue();
    wq->removeRequestHandler(mWorkQueueChannel, this);
    wq->removeResponseHandler(mWorkQueueChannel, this);

    _____________________________________________________________________________________________________________________________________________________

    2、准备两个结构体,用于记录Request/Response的Contex,Request与Response容易看错,注意颜色区分

    /// A data holder for communicating with the background derived data update
    struct DerivedDataRequest
    {
           Terrain* terrain;
               _OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const DerivedDataRequest& r)
           { return o; }               // 这个函数要导出
    };

    /// A data holder for communicating with the background derived data update
    struct DerivedDataResponse
    {
           Terrain* terrain;
           PixelBox* lightMapBox;
           _OgreTerrainExport friend std::ostream& operator<<(std::ostream& o, const DerivedDataResponse& r)
           { return o; }       // 这个函数要导出              
    };

    _____________________________________________________________________________________________________________________________________________________

    3、重载以下4个函数

    /// WorkQueue::RequestHandler override
    bool canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ);
    /// WorkQueue::RequestHandler override
    WorkQueue::Response* handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ);
    /// WorkQueue::ResponseHandler override
    bool canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ);
    /// WorkQueue::ResponseHandler override
    void handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ);

    其中handleRequest是在多线程中处理实际加载数据的函数,具体的读取、创建之类的操作都在此完成。

    对于 canHandleRequest、canHandleResponse基本上就是判定是不是自己的处理对象,一般可以不管,但为了谨慎起见还是需要对请求任务判定,以免多个同类任务执行时会有冲突:

    bool Terrain::canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
    {
           DerivedDataRequestddr = any_cast<DerivedDataRequest>(req->getData());
           // only deal with own requests
           // we do this because if we delete a terrain we want any pending tasks to be discarded
           if (ddr.terrain != this)
                   return false;
           else
                   return RequestHandler::canHandleRequest(req, srcQ);

    }

    //---------------------------------------------------------------------
    bool Terrain::canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
    {
           DerivedDataRequestddreq = any_cast<DerivedDataRequest>(res->getRequest()->getData());
           // only deal with own requests
           // we do this because if we delete a terrain we want any pending tasks to be discarded
         if (ddreq.terrain != this)
                   return false;
           else
                   return true;

    }

    上面就是要注意用any转型时取得的源对象是什么。(res->getRequest()->getData() 与 req->getData())

    对于handleRequest最后要做的就是返回一个新的处理结果:

    WorkQueue::Response* Terrain::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
    {

           DerivedDataResponse ddres;

           把操作的结果都放到ddres中返回给主线程中去处理

           WorkQueue::Response* response = OGRE_NEW WorkQueue::Response(req, true, Any(ddres));
           return response;
    }

    _____________________________________________________________________________________________________________________________________________________

    4、添加具体的任务请求(部分代码省略)

    DerivedDataRequest req;
    req.terrain = this;
    Root::getSingleton().getWorkQueue()->addRequest(
           mWorkQueueChannel, WORKQUEUE_DERIVED_DATA_REQUEST,
           Any(req), 0, synchronous);


    其中 :const uint16 Terrain::WORKQUEUE_DERIVED_DATA_REQUEST = 1,对于同个对象,如果有不同的数据操作类型,可以用多个不同的ID区别。

    _____________________________________________________________________________________________________________________________________________________

    注意:在析构时可能还有请求的任务没完成,因此要等待任务完成后才能移除,要不会CRASH。这个需要自己维护一个标记,并让线程队列处理。基本上是在addRequest的时候设置为true,在handleResponse时设置为false:

    bool mDerivedDataUpdateInProgress;

    void Terrain::waitForDerivedProcesses()
    {
           while (mDerivedDataUpdateInProgress)
           {
                   // we need to wait for this to finish
                   OGRE_THREAD_SLEEP(50);
                   Root::getSingleton().getWorkQueue()->processResponses();
           }

    }

    void Terrain::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)

       mDerivedDataUpdateInProgress = false;  

     

    void Terrain::updateDerivedDataImpl(const Rect& rect, const Rect& lightmapExtraRect,
           bool synchronous, uint8 typeMask)
    {
           mDerivedDataUpdateInProgress = true;
           Root::getSingleton().getWorkQueue()->addRequest(
                   mWorkQueueChannel, WORKQUEUE_DERIVED_DATA_REQUEST,
                   Any(req), 0, synchronous);

    }

  • 相关阅读:
    npm 一些常用的命令
    Angular Encapsulation
    隐藏scrollbar
    Vue生命周期详解(1)- 单个组件
    如何自己制作iconfont
    day07-2018-10--25 深浅拷贝
    day06-2018-10--24 小数据池和编码
    day05-2018-10--23 字典
    day04-2018-10--22python基础
    day03-2018-10-19-python基础
  • 原文地址:https://www.cnblogs.com/pulas/p/2358073.html
Copyright © 2020-2023  润新知