现在的位置: 首页 > 综合 > 正文

Ogre多线程加载问题

2013年03月15日 ⁄ 综合 ⁄ 共 5584字 ⁄ 字号 评论关闭

Ogre 1.7中,对多线程的支持有三个选择:

要在Ogre 1.7中使用多线程:

1        OgreBuildSettings.h改写2

1        OGRE_THREAD_SUPPORT 2 //
通过ResourceBackgroundQueue实现。

1        OGRE_THREAD_PROVIDER 3 // TBB library provides threadingfunctionality

我采用C++的并行编程模板库Threading
Building Blocks
。采用CMake构造的需要把TBB的文件拷贝到OgreDependence的相关目录下。

Ogre 1.7
Threading changes

·        WorkQueue added to accept generalised work items to beexecuted in background worker threads

·        WorkQueue starts the number of workers based on hardware, orcan be told to start a different number

·        Main Ogre WorkQueue is in Root::getWorkQueue. You can alsosubclass WorkQueue and provide your own if you want

·        ResourceBackgroundQueuenow uses WorkQueue instead of using its own queueand can have multipletasks running at
once

·        New focus on data-driven, task-based parallel execution withseparation of GPU and CPU activities

·        Boost, POCO and Thread Building Blocks supported as threadingback-ends (Boost preferred)

·        All Ogre thread support will use WorkQueue in future

备注:1.7添加了一个Character Sample,其中SinbadCharacterController有参考价值。

 

WorkQueue
使用方法

 

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

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 thebackground derived data update

struct DerivedDataRequest
{
       Terrain* terrain;
           _OgreTerrainExport friendstd::ostream& operator<<(std::ostream& o, constDerivedDataRequest& r)

       { return o; }               //
这个函数要导出

};

/// A data holder forcommunicating with the background derived data update

struct DerivedDataResponse
{
       Terrain* terrain;
       PixelBox* lightMapBox;
       _OgreTerrainExport friendstd::ostream& operator<<(std::ostream& o, constDerivedDataResponse& 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, constWorkQueue* 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基本上就是判定是不是自己的处理对象,一般可以不管,但为了谨慎起见还是需要对请求任务判定,以免多个同类任务执行时会有冲突:

boolTerrain::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 deletea terrain we want any pending tasks to be discarded
       if (ddr.terrain != this)
               return false;
       else
               returnRequestHandler::canHandleRequest(req, srcQ);

}

//---------------------------------------------------------------------
bool Terrain::canHandleResponse(const WorkQueue::Response* res, constWorkQueue* srcQ)

{
       DerivedDataRequestddreq =any_cast<DerivedDataRequest>(res->getRequest()->getData());

       // only deal with own requests
       // we do this because if we deletea 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_NEWWorkQueue::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:

boolmDerivedDataUpdateInProgress;

voidTerrain::waitForDerivedProcesses()

{
       while(mDerivedDataUpdateInProgress)
       {
               // we need to wait forthis to finish
               OGRE_THREAD_SLEEP(50);
              Root::getSingleton().getWorkQueue()->processResponses();
       }

}

voidTerrain::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)

   mDerivedDataUpdateInProgress = false; 

 

void Terrain::updateDerivedDataImpl(constRect& rect, const Rect& lightmapExtraRect,

       bool synchronous, uint8 typeMask)
{
       mDerivedDataUpdateInProgress =true;
      Root::getSingleton().getWorkQueue()->addRequest(
               mWorkQueueChannel,WORKQUEUE_DERIVED_DATA_REQUEST,
               Any(req), 0, synchronous);

}

 

 

抱歉!评论已关闭.