Sign in to follow this  
Tesshu

Locked container

Recommended Posts

Does anyone have a nice solution to detecting when an STL container is being modified while it's being iterated over? In the following code, I would like to assert if listpObjects gets modified as a side effect of pObject->update(). I don't want to put an if inside the loop either.
typedef std::list< Object* >	ObjectPtrList;
typedef ObjectPtrList::iterator	ObjectPtrListIter;
//==================================================================================================
//==================================================================================================
void UpdateAll( ObjectPtrList& listpObjects )
{
	for( ObjectPtrListIter iter = listpObjects.end(); iter != listpObjects.end(); ++iter )
	{
		Object*	pObject = *iter;
		pObject->update();
	}
}

I wrote a very simple wrapper for std::list that acquires the list but it's not all that hot, plus I will have to write it for other containers.
//==================================================================================================
//==================================================================================================
template < typename TYPE >
class STL_LockList
{
private:
	//----------------------------------------------------------------------------------------------
	typedef	std::list< TYPE >	ListType;

	//----------------------------------------------------------------------------------------------
	bool			m_bLocked;
	ListType		m_list;

public:
	//----------------------------------------------------------------------------------------------
	STL_LockList() : m_bLocked( false ) 
	{

	}
	~STL_LockList()
	{
		T_Assert( m_bLocked == false );
	}

	//----------------------------------------------------------------------------------------------
	ListType&		lock()
	{
		T_Assert( m_bLocked == false );
		m_bLocked = true;
		return m_list;
	}
	//----------------------------------------------------------------------------------------------
	void			unlock()
	{
		T_Assert( m_bLocked == true );
		m_bLocked = false;
	}

	//----------------------------------------------------------------------------------------------
	void			push_front( const TYPE& item )
	{
		T_Assert( m_bLocked == false );
		m_list.push_front( item );
	}
	//----------------------------------------------------------------------------------------------
	void			push_back( const TYPE& item )
	{
		T_Assert( m_bLocked == false );
		m_list.push_back( item );
	}
	//----------------------------------------------------------------------------------------------
	void			remove( const TYPE& item )
	{
		T_Assert( m_bLocked == false );
		m_list.remove( item );
	}
};

Share this post


Link to post
Share on other sites
I'm assuming this is for concurrency work.

the STL is not threadsafe. you should look into using a thread-safe library for those containers that need to support concurrent access; and use the STL for those that you know will only be accessed in a single thread.

intel released a multi-thread safe library with some container primitives that are simple to use:
http://www.intel.com/cd/software/products/asmo-na/eng/294797.htm

-me

Share this post


Link to post
Share on other sites
Quote:
Original post by Palidine
I'm assuming this is for concurrency work.


No it's not. It's just to protect against bugs, hence the assert. These lists are for stuff like Physics::UpdateAll(), AI::UpdateAll() etc. It can be a hard bug to trace down if somehow one of these lists is modified, say an object being destroyed, while I am iterating over it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Tesshu
Quote:
Original post by Palidine
I'm assuming this is for concurrency work.


No it's not. It's just to protect against bugs, hence the assert. These lists are for stuff like Physics::UpdateAll(), AI::UpdateAll() etc. It can be a hard bug to trace down if somehow one of these lists is modified, say an object being destroyed, while I am iterating over it.


No, there is no reliable way.

Use containers where iterators aren't invalidated, or structure your code in such a way that it cannot happen. std::list is one way, although performance penalty is likely unacceptable.

This is a considerable problem with events and callbacks, where callback may modify subscriptions while the dispatcher is iterating through the same collection.

There's are solutions, but neither is the silver bullet.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus


There's are solutions, but neither is the silver bullet.


Thank you for the link, it's a very good read. I actually had the method of using a vector and instead of removing the element, I assigned NULL to it. Thing is that you have to put an if NULL in the loop, which makes me feel dirty. I decided to make it policy not not allow updating the list at all while iterating over it.

I was just hoping that there would be version of STL that had this kind of support :(

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this