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

From: Gabriel M. Beddingfield <gabrbedd@email-addr-hidden>
Date: Mon Feb 21 2011 - 00:46:17 EET

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
_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@email-addr-hidden
http://lists.linuxaudio.org/listinfo/linux-audio-dev
Received on Mon Feb 21 04:15:01 2011

This archive was generated by hypermail 2.1.8 : Mon Feb 21 2011 - 04:15:01 EET