Thread safe positions

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Thread safe positions

Post by Transporter »

Hi,

I have a seperate thread to calculate positions of about 50 nodes. But calling setPosition of the nodes creates an vs error message:

Assertion failed!
Programm: OgreMain_d.dll
File: OgreNode.h
Line: 653
Expression: !mCachedTransformOutOfDate

Is setPosition not thread safe? I can move setPosition/setOrientation to an other place, if neccesary. Where is the best place to update positions?

Thanks,
Transporter
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5476
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1358

Re: Thread safe positions

Post by dark_sylinc »

More information on how your threads are running and the hierarchy setup is needed.
Updating and retrieving positions can be done in a thread safe manner, but no lock inside is performed, thus care must be taken.

I'll link as a reminder my comment on the same issue.
Note this code how it updates all nodes from multiple threads.
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Thread safe positions

Post by Transporter »

Thanks a lot! I'm very sorry but I forget about https://ogre3d.atlassian.net/browse/OGRE-406. :oops:

I'll create a thread safe queue where I can save rotations/translation and update the nodes in frameStart.

Edit: Example for 64 threads

TutorialApplication.h

Code: Select all

#include "BaseApplication.h"
#include <boost/lockfree/queue.hpp>

#define TESTTHREADING 8

class TutorialApplication : public BaseApplication
{
private:
	typedef struct
	{
		Ogre::SceneNode* node;
		Ogre::Real w, x, y, z;
	} ROTATION;

	boost::shared_ptr<boost::thread> mThreads[TESTTHREADING * TESTTHREADING];
	boost::lockfree::queue<ROTATION, boost::lockfree::fixed_sized<false>> mQueue;

public:
	TutorialApplication(void);
	virtual ~TutorialApplication(void);

protected:
	virtual void createScene(void);
	virtual bool updateFrame(const Ogre::FrameEvent& evt);

	void threadProc(Ogre::SceneNode* pNode);
};
TutorialApplication.cpp

Code: Select all

void TutorialApplication::createScene(void)
{
	srand(time(NULL));
	Ogre::LogManager::getSingletonPtr()->logMessage("Working Threads: " + Ogre::StringConverter::toString(TESTTHREADING * TESTTHREADING));
	Ogre::MeshPtr sinbad;
	for(size_t i = 0; i < TESTTHREADING; i++)
	{
		for(size_t j = 0; j < TESTTHREADING; j++)
		{
			Ogre::SceneNode* node = mSceneMgr->getRootSceneNode(Ogre::SCENE_DYNAMIC)->createChildSceneNode(Ogre::SCENE_DYNAMIC);
			Ogre::Entity* entity = mSceneMgr->createEntity("Sinbad.mesh", Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, Ogre::SCENE_DYNAMIC);
			if(sinbad.isNull()) sinbad = entity->getMesh();
			node->attachObject(entity);
			node->setPosition((Ogre::Real)i * 3.0f * sinbad->getBoundingSphereRadius(), 0.0f, (Ogre::Real)j * 3.0f * sinbad->getBoundingSphereRadius());
			mThreads[i * TESTTHREADING + j] = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&TutorialApplication::threadProc, this, node)));
		}
	}

	mCamera->setPosition(0.0f, (Ogre::Real)TESTTHREADING * 5.0f, 0.0f);
	mCamera->lookAt((Ogre::Real)TESTTHREADING * 1.5f * sinbad->getBoundingSphereRadius(), 0.0f, (Ogre::Real)TESTTHREADING * 1.5f * sinbad->getBoundingSphereRadius());
	mSceneMgr->setAmbientLight(Ogre::ColourValue::White);
}

bool TutorialApplication::updateFrame(const Ogre::FrameEvent& evt)
{
	ROTATION rot;
	while(mQueue.pop(rot))
	{
		rot.node->setOrientation(rot.w, rot.x, rot.y, rot.z);
	}
	return true;
}

void TutorialApplication::threadProc(Ogre::SceneNode* pNode)
{
	srand((unsigned int)(void*)pNode);
	ROTATION rot = { pNode, 0.0f, 0.0f, 0.0f, 0.0f };
	while(!mShutDown)
	{
		Ogre::Quaternion r(Ogre::Degree((Ogre::Real)(rand() % 360)), Ogre::Vector3::UNIT_Y);
		rot.w = r.w;
		rot.x = r.x;
		rot.y = r.y;
		rot.z = r.z;

		mQueue.push(rot);

		int wait = rand() % 100 + 1;
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		Sleep(wait);
#else
		usleep(wait * 1000);
#endif
	}
}
I've added a virtual function bool updateFrame(const Ogre::FrameEvent& evt) to BaseApplication and call it from frameStart

Code: Select all

bool BaseApplication::frameStarted(const Ogre::FrameEvent& evt)
{
	return updateFrame(evt);
}
This is just to reduce changes on BaseApplication.