OGRE Wiki
Support and community documentation for Ogre3D
Ogre Forums
ogre3d.org
Log in
Username:
Password:
CapsLock is on.
Remember me (for 1 year)
Log in
Home
Tutorials
Tutorials Home
Basic Tutorials
Intermediate Tutorials
Mad Marx Tutorials
In Depth Tutorials
Older Tutorials
External Tutorials
Cookbook
Cookbook Home
CodeBank
Snippets
Experiences
Ogre Articles
Libraries
Libraries Home
Alternative Languages
Assembling A Toolset
Development Tools
OGRE Libraries
List of Libraries
Tools
Tools Home
DCC Tools
DCC Tutorials
DCC Articles
DCC Resources
Assembling a production pipeline
Development
Development Home
Roadmap
Building Ogre
Installing the Ogre SDK
Setting Up An Application
Ogre Wiki Tutorial Framework
Frequently Asked Questions
Google Summer Of Code
Help Requested
Ogre Core Articles
Community
Community Home
Projects Using Ogre
Recommended Reading
Contractors
Wiki
Immediate Wiki Tasklist
Wiki Ideas
Wiki Guidelines
Article Writing Guidelines
Wiki Styles
Wiki Page Tracker
Ogre Wiki Help
Ogre Wiki Help Overview
Help - Basic Syntax
Help - Images
Help - Pages and Structures
Help - Wiki Plugins
Toolbox
Freetags
Categories
List Pages
Structures
Trackers
Statistics
Rankings
List Galleries
Ogre Lexicon
Comments
History: How to use the WorkQueue
View page
Source of version: 6
(current)
If you have some bigger tasks which could be done in parallel or where the results are just needed later, why not make use of your bored CPU cores and handle it parallel? This is where the WorkQueue comes in. A WorkQueue takes requests, executes them and notice you with a callback. !Defining the request Your class handling the requests needs to implement some interfaces like this: {CODE(wrap="1", colors="c++")}class Foo : public WorkQueue::RequestHandler, public WorkQueue::ResponseHandler { /// Implementation for WorkQueue::RequestHandler WorkQueue::Response* handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ); /// Implementation for WorkQueue::ResponseHandler void handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ); }{CODE} handleRequest() will be the code being executed in parallel in a thread and handleResponse is the callback when the request is done. You can also decide, whether you can currently handle requests and responses by overriding these methods: {CODE(wrap="1", colors="c++")}bool canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ) bool canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ){CODE} Note, that you basically don't have access to the rendersystem within handleRequest as it will be in another thread! Actually, you could define your WorkQueue with "workersCanAccessRenderSystem" set to true, but now you have some performance drawbacks due to heavy locking. So it might be better to just handle CPU heavy things in the request. You are likely to need some data within handleRequest and handleResponse. A struct might already do it: {CODE(wrap="1", colors="c++")}typedef struct FooRequest { int a; int b; friend std::ostream& operator<<(std::ostream& o, const FooRequest& r) { return o; } } FooRequest;{CODE} Note the implementation of the operator<<. The WorkQueue requires this. A possible implementation of the two functions could now look like this: {CODE(wrap="1", colors="c++")} WorkQueue::Response* Foo::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ) { FooRequest cReq = any_cast<FooRequest>(req->getData()); // Do some heavy work. return OGRE_NEW WorkQueue::Response(req, true, Any()); // Indicate, that everything went well. In case of error, return a response with false as second parameter. } void Foo::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ) { // Just do something if the request was a success. if (res->succeeded()) { FooRequest cReq = any_cast<ChunkRequest>(res->getRequest()->getData()); // React how you need it. } }{CODE} !Let the WorkQueue handle the requests. Now that you have setup your request, it's time to actually execute them. First, you need to setup the WorkQueue so it takes your class as handler. Assume the following is within the Foo class above. {CODE(wrap="1", colors="c++")}WorkQueue* wq = Root::getSingleton().getWorkQueue(); uint16 workQueueChannel = wq->getChannel("Ogre/FooRequest"); wq->addRequestHandler(workQueueChannel, this); wq->addResponseHandler(workQueueChannel, this);{CODE} This grabs the workqueue instance from the root and creates a named channel. This channel is then used to register the foo instance (this) as request and response handler. !Add a request Everything is prepared to fill the WorkQueue with requests now. Do this as often now as you need to start the work: {CODE(wrap="1", colors="c++")} const Ogre::uint16 WORKQUEUE_LOAD_REQUEST = 1; // You can use this ID to differentiate between request types if needed FooRequest req; req.a = 1; req.b = 2; wq->addRequest(workQueueChannel, WORKQUEUE_LOAD_REQUEST, Any(req));{CODE} To execute your request synchronously instead of parallel, you could hand it to the WorkQueue like this: {CODE(wrap="1", colors="c++")}wq->addRequest(workQueueChannel, WORKQUEUE_LOAD_REQUEST, Any(req), 0, false);{CODE} !Wait for all requests There could be a situation, where you want to wait for all your request until they are done. To do so, a quick and easy way would be to add a static counter to the class Foo. Increment it just before you add your request and decrement it in the responseHandler. Now you can add a loop right after the requests are all added which wait until the counter gets to zero (indicating that all requests are done now): {CODE(wrap="1", colors="c++")}while(mRequestsBeingProcessed) { OGRE_THREAD_SLEEP(0); wq->processResponses(); }{CODE} The sleep is there to let the main thread sleep a tiny amount of time on every iteration. This way, one core isn't stalled with 100% waiting loop, but can also do some management work. !Clean up When you are done with everything, it's a good idea to clean up a bit by unregistering your Foo instance from the WorkQueue: {CODE(wrap="1", colors="c++")} wq->removeRequestHandler(workQueueChannel, this); wq->removeResponseHandler(workQueueChannel, this);{CODE} !Resume You know now enough about the WorkQueue to make something useful with it. There are a lot of other utilities coming with it like aborting requests etc.. Have a look at the API documentation and explore. :)
Search by Tags
Search Wiki by Freetags
Latest Changes
Minimal Ogre Collision
Artifex Terra
OpenMB
Advanced Mogre Framework
MogreSocks
Critter AI
Mogre Add-ons
MOGRE
Mogre MyGUI wrapper
MOGRE Editable Terrain Manager
...more
Search
Find
Advanced
Search Help
Online Users
54 online users