[LAD] Finding Deadlock causes in multithreaded C++ using gdb

Gabriel M. Beddingfield gabrbedd at gmail.com
Sun Feb 20 22:46:17 UTC 2011


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/Engine.hpp
[2] http://gitorious.com/composite/composite/blobs/master/src/Tritium/src/Engine.cpp



More information about the Linux-audio-dev mailing list