Jump to content
  • Advertisement
Sign in to follow this  
FFMG

Hep with thread logic to prevent deadlock

This topic is 3081 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I am trying to write a thread safe class, (in C++) and this is basically what I have now.

// -- pseudo code
UpdateValue( index, x )
{
Enter_Thread_Lock
// check that pointer _myMap[index] does exist
if( value != _myMap[index]->current_value_value )
{
_myMap[index]->current_value_value = value
_myMap[index]->NotifyOtherThreadsOfChangedValue()
}
Release_Thread_Lock
}
// -- pseudo code

Of course in the example above, NotifyOtherThreadsOfChangedValue() could itself cause a call to UpdateValue() and in that case I would have a deadlock...

The obvious solution would be
// -- pseudo code
UpdateValue( index, value )
{
Enter_Thread_Lock
// check that pointer _myMap[index] does exist
if( value == _myMap[index]->current_value_value )
{
Release_Thread_Lock
}
else
{
_myMap[index]->current_value_value = value
Release_Thread_Lock
_myMap[index]->NotifyOtherThreadsOfChangedValue( ... )
}
}
// -- pseudo code

but in the case above another thread would/could delete the value of the pointer _myMap[index] altogether and in that case my app would explode.

Or, in a more obsure issue it is possible that 2 calls to _myMap[index]->NotifyOtherThreadsOfChangedValue( ... ) would be sent for out of sync values.

So, how would you solve this possible re-entry problem, (note that I do not want to prevent the re-entries itself).

Thanks

FFMG

Share this post


Link to post
Share on other sites
Advertisement
What threading API are you using? There are some pretty easy ways to do that thread notification that don't involve possibly deadlocking the first thread, but it depends on the system you target (OS and possibly wrapper library).

Share this post


Link to post
Share on other sites
POSIX supports recursive mutexes. This is a good read.
http://stackoverflow.com/questions/187761/recursive-lock-mutex-vs-non-recursive-lock-mutex

Cheers!

Share this post


Link to post
Share on other sites
recursion is bad for many reasons one being thread safety with locks. The answer I suggest is to use a class to manage the locking and unlocking. Have the class get the current thread when locking and dont lock if the thread is the same. Also dont mark the class as locked so it wont unlock in the destructor. This will also save you the complication of dealing with functions with multiple exit points and you forgetting one. As a note your design is bad in that it is possible at least in a wierd case for the function to keep calling itself. You should pass a counter at the least to guarantee it doesnt do a stack overflow.

Share this post


Link to post
Share on other sites
Quote:
Original post by FFMG
Of course in the example above, NotifyOtherThreadsOfChangedValue() could itself cause a call to UpdateValue() and in that case I would have a deadlock...


A very good law/rule-of-thumb to follow is to never call "unknown code" while holding a lock, that is virtual functions, function pointers and "callbacks" of other kinds.

Can you not call NotifyOtherThreadsOfChangedValue() outside of that critical section?

Quote:
Original post by FFMG
The obvious solution would be
// -- pseudo code
UpdateValue( index, value )
{
Enter_Thread_Lock
// check that pointer _myMap[index] does exist
if( value == _myMap[index]->current_value_value )
{
Release_Thread_Lock
}
else
{
_myMap[index]->current_value_value = value
Release_Thread_Lock
_myMap[index]->NotifyOtherThreadsOfChangedValue( ... )
}
}
// -- pseudo code

but in the case above another thread would/could delete the value of the pointer _myMap[index] altogether and in that case my app would explode.


One solution you might consider is using a boost::shared_ptr to hold the values in your map. You make a local copy inside your critical section and that will guarantee that the object still exists outside the critical section.

But I suspect that a refinement in the design itself might be a better approach. So might I ask

1. what invariant does your lock protect? And can that invariant be broken down in to smaller data-independent invariants?
2. what does NotifyOtherThreadsOfChangedValue() do? Or, what does it mean to "tell a thread something" in your system? It's often better to arrange the code to think in terms of tasks rather than threads.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!