Skip to main content

History: Threading

Preview of version: 7

User comments

This is mainly just a rewording of this forum thread (year 2005) so go there for the full answer.


Sinbad wrote:

You should thread things that naturally fall into the background, ie to be spread over multiple frames. That's AI, buffering of streaming data, but probably not physics (because you need to keep it in sync with the frame rate if it's not going to look weird). None of these things are Ogre itself. Due to the fact that the graphics are the most noticeable thing, and that the GPU is asynchronous anyway, rendering processes are rarely farmed out to the background, so there's generally no need for thread safety. Projects which use threading thread non-graphical things.

The one case where it might be useful is background loading using the resource system. In Azathoth the resource system is (experimentally) thread safe if you set OGRE_THREAD_SUPPORT to 1, allowing you to load things in a background thread if you want. But that's only the resource system, nothing else is thread safe, and in my opinion has no need to be. We use boost::threads for this, personally it seemed a much better solution than anything else I've seen (it reminds me of Java threads).


AlphaBeta wrote:

Keep in mind you don't need threads to run systems at varying rates (keep countdowns, if time is up step the system, if not move on).
If you're using ogre for a game threading isn't really necessary (like sinbad said, graphics are already asynchronous).

For things like physics, multi-steps are often done (instead of updating the physics simulation 30 milliseconds, you might have it do 15 milliseconds 2 times. Physics simulations get less accurate with bigger updates, which doesn't apply to most other systems).

You wouldn't want to simply run a physics update multiple times for each graphics one, you should work it out with timers and countdowns.


QSilver wrote:

I should point out that even though Ogre is not thread-safe, there is no reason why your application cannot use threads. It just means that you cannot have multiple threads which deal with Ogre.

As long as you make sure that only a single thread handles all your Ogre-related tasks, you are free to run your sound engine or AI scripts in other threads.

Example

This example is based on the Tutorial Framework and displays the ogre head. The position of the head is calculated in a new thread using boost. The result is used in main thread to move the head.
TutorialApplication.h

Copy to clipboard
#ifndef __TutorialApplication_h_ #define __TutorialApplication_h_ #include "BaseApplication.h" #include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/shared_ptr.hpp> #include <boost/random/linear_congruential.hpp> #include <boost/random/uniform_real.hpp> #include <boost/random/variate_generator.hpp> #include <boost/generator_iterator.hpp> class TutorialApplication : public BaseApplication { public: TutorialApplication(void); virtual ~TutorialApplication(void); // true if a stop was requested, false otherwise volatile bool m_bStopRequested; // thread pointer boost::shared_ptr<boost::thread> m_Thread; // Mutext for data shareing boost::mutex m_Mutex; // share data Ogre::Vector3 m_headPosition; protected: virtual void createScene(void); virtual void destroyScene(void); virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt); Ogre::SceneNode* m_pHeadNode; private: void run(); void createPosition(); }; #endif // #ifndef __TutorialApplication_h_

TutorialApplication.cpp

Copy to clipboard
#include "TutorialApplication.h" //------------------------------------------------------------------------------------- TutorialApplication::TutorialApplication(void) { m_pHeadNode = NULL; m_bStopRequested = false; } //------------------------------------------------------------------------------------- TutorialApplication::~TutorialApplication(void) { } //------------------------------------------------------------------------------------- void TutorialApplication::createScene(void) { // Set the scene's ambient light mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f)); // Create an Entity Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); // Create a SceneNode and attach the Entity to it m_pHeadNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode"); m_pHeadNode->attachObject(ogreHead); // Create a Light and set its position Ogre::Light* light = mSceneMgr->createLight("MainLight"); light->setPosition(20.0f, 80.0f, 50.0f); // Create the thread and start work assert(!m_Thread); m_Thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&TutorialApplication::run, this))); } //------------------------------------------------------------------------------------- void TutorialApplication::destroyScene(void) { // Stops the thread assert(m_Thread); m_bStopRequested = true; m_Thread->join(); // Destroy scene BaseApplication::destroyScene(); } //------------------------------------------------------------------------------------- // See Basic Tutorial 4 bool TutorialApplication::frameRenderingQueued(const Ogre::FrameEvent& evt) { bool ret = BaseApplication::frameRenderingQueued(evt); // Update position of ogre head if(m_pHeadNode != NULL) { // Lock variable boost::unique_lock<boost::mutex> lock(m_Mutex); // Process data in main thread m_pHeadNode->setPosition(m_headPosition); } return ret; } // Unlock //------------------------------------------------------------------------------------- void TutorialApplication::run() { Ogre::LogManager::getSingletonPtr()->logMessage("*** Entering new thread ***"); while(!m_bStopRequested) { boost::this_thread::sleep(boost::posix_time::seconds(1)); // use a seperate function to lock variable and unlock it with returning createPosition(); } Ogre::LogManager::getSingletonPtr()->logMessage("*** Leaving new thread ***"); } //------------------------------------------------------------------------------------- void TutorialApplication::createPosition() { // Init random generator boost::minstd_rand generator(static_cast<unsigned int>(std::time(0))); boost::uniform_real<> uni_dist(0, 100); boost::variate_generator<boost::minstd_rand&, boost::uniform_real<>> uni(generator, uni_dist); // Lock variable boost::unique_lock<boost::mutex> lock(m_Mutex); // Set new position m_headPosition = Ogre::Vector3(uni(), uni(), uni()); } // Unlock

History

Information Version
Wed 02 of Apr, 2014 06:48 GMT-0000 Transporter Update to work with OGRE 2.0 8
Wed 18 of Jul, 2012 09:52 GMT-0000 Transporter Update example code (add log entries, code format) 7
Fri 01 of Jun, 2012 16:04 GMT-0000 Transporter Add multithreading example 6
Sat 09 of Jan, 2010 04:28 GMT-0000 jacmoe 5
Sun 03 of Jan, 2010 01:01 GMT-0000 jacmoe 4
Fri 25 of Dec, 2009 23:21 GMT-0000 jacmoe 3
Fri 25 of Dec, 2009 23:21 GMT-0000 jacmoe 2
Mon 10 of Nov, 2008 20:10 GMT-0000 OgreWikiBot Robot: Cosmetic changes 1