Hi Harry,
On Sun, 20 Feb 2011, Harry Van Haaren wrote:
I'm working on a mulithreaded version of my pet
project, and I've now
managed to deadlock one thread,
which in turn makes the GUI thread wait for a mutex lock, and then finally
segfaults the whole program :-)
So I'm looking for pointers on how best to find a deadlock's cause using
gdb?
Other advice / good articles on the topic etc welcome!
Thanks for reading, -Harry
In addition to the excellent suggestions from other folks...
here's another approach.
In Hydrogen/Composite, there is a central, critical audio
lock.[3] For this lock, we set up a system for the central
audio lock that would "log" the line of code that last
locked the mutex. See [1] and [2]. Whenever you deadlock,
you can look at this->d->__locker to see the file and line
number where the mutex was last locked.
This solution was suggested to us by Krzysztof Foltman, and
once saved me a ton of time. Thanks, Krzysztof!
The important parts are:
/**
* Convenience macro for locking the Engine.
*/
#ifndef RIGHT_HERE
#define RIGHT_HERE __FILE__, __LINE__, __PRETTY_FUNCTION__
#endif
And:
class Engine : public EngineInterface
{
public:
//...
///////////////////////////////////////
// THE BIG LOCK
///////////////////////////////////////
/* Mutex locking and unlocking
*
* Easy usage: Use the RIGHT_HERE macro like this...
* engine->lock( RIGHT_HERE );
*
* More complex usage: The parameters file and function
* need to be pointers to null-terminated strings that are
* persistent for the entire session. This does *not*
* include the return value of std::string::c_str(), or
* QString::toLocal8Bit().data().
*
* Notes: The order of the parameters match GCC's
* implementation of the assert() macros.
*/
void lock( const char* file, unsigned int line, const char* function );
bool try_lock( const char* file, unsigned int line, const char* function );
void unlock();
//...
}
And:
void Engine::lock( const char* file, unsigned int line, const char* function )
{
d->__engine_mutex.lock();
d->__locker.file = file;
d->__locker.line = line;
d->__locker.function = function;
}
bool Engine::try_lock( const char* file, unsigned int line, const char* function )
{
bool locked = d->__engine_mutex.tryLock();
if ( ! locked ) {
// Lock not obtained
return false;
}
d->__locker.file = file;
d->__locker.line = line;
d->__locker.function = function;
return true;
}
void Engine::unlock()
{
// Leave "d->__locker" dirty.
d->__engine_mutex.unlock();
}
-gabriel
[1]
http://gitorious.com/composite/composite/blobs/master/src/Tritium/Tritium/E…
[2]
http://gitorious.com/composite/composite/blobs/master/src/Tritium/src/Engin…