0

I have a test program that I wrote to try and debug a GMutex issue that I am having and I cannot seem to figure it out. I am using the class below to lock and unlock a mutex within a scoped context. This is similar to BOOST's guard.

   /// @brief Helper class used to create a mutex.
   ///
   /// This helper Mutex class will lock a mutex upon creation and unlock when deleted.
   /// This class may also be referred to as a guard.
   ///
   /// Therefore this class allows scoped access to the Mutex's locking and unlocking operations
   /// and is good practice since it ensures that a Mutex is unlocked, even if an exception is thrown.
   ///
   class cSessionMutex
   {
      GMutex* apMutex;
      /// The object used for logging.
      mutable cLog aLog;

   public:
      cSessionMutex (GMutex *ipMutex) : apMutex(ipMutex), aLog ("LOG", "->")
      {
         g_mutex_lock(apMutex);
         aLog << cLog::msDebug << "MUTEX LOCK " << apMutex << "," << this << cLog::msEndL;
      }

      ~cSessionMutex ()
      {
         aLog << cLog::msDebug << "MUTEX UNLOCK " << apMutex << "," << this << cLog::msEndL;
         g_mutex_unlock(apMutex);
      }
   };

Using this class, I call it as follows:

bool van::cSessionManager::RegisterSession(const std::string &iSessionId)
{
cSessionMutex lRegistryLock (apRegistryLock);

// SOME CODE
}

where apRegistryLock is a member variable of type GMutex* and is initialized using g_mutex_new() before I ever call RegisterSession.

With this said, when I run the application with several threads, I sometimes notice at the beginning, when RegisterSession is called for the first few times that the log (from the constructor above)

[DEBUG] LOG.-> - MUTEX LOCK 0x26abb40,0x7fc14ad7ae10
[DEBUG] LOG.-> - MUTEX LOCK 0x26abb40,0x7fc14af7ce10

is logged twice in a row with the same mutex but different instance; therefore, suggesting that the mutex is being locked twice or the second lock is simply being ignored - which is seriously bad.

Moreover, it is worth noting that I also check to see if these logs were initiated from the same thread using the g_thread_self() function, and this returned two separate thread identifiers; thus, suggesting that the mutex was locked twice from separate threads.

So my question is, how is it possible for this to occur?

bbazso
  • 1,959
  • 6
  • 22
  • 30
  • Note that the answer below is only partially correct. It is not correct in all cases since since it really depends on the implementation. On my system running POSIX threads in Ubuntu and/or Linux RH, the second lock within the same thread is not ignored but rather it will actually lock and by extension deadlock (wrote a test for this to confirm). But in the case above, it just does not do this when running it for the first time. I tried running valgrind --tool=drd and --tool=helcheck on my test application and they basically confirmed what I am seeing: The second lock seems to get ignored. – bbazso Apr 07 '11 at 15:21
  • Are you sure this isn't just your log messages being re-ordered due to buffering? – Spudd86 Apr 07 '11 at 16:36
  • I thought that it might be the logging and so I also but an assert in the code if an access is made while locked and this assert is indeed triggered. So this seems to suggest that there really is a problem with the mutex lock and not the way I'm testing it. – bbazso Apr 07 '11 at 17:13

2 Answers2

2

If it's called twice in the same call chain in the same thread this could happen. The second lock is typically (although not always) ignored. At least in pthreads it's possible to configure multiple locks as counted.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Some implementations of mutex allow for the same thread to lock the mutex twice. It must then be unlocked a correspondingly two times. – Andy Finkenstadt Apr 06 '11 at 21:00
  • It's called recursive mutexes. If you prefer non-recursive ones (like the POSIX standard), refer [here](http://stackoverflow.com/questions/1896581/how-do-i-make-the-mutex-not-be-recusive) for hints – sehe Apr 06 '11 at 21:42
  • Please note that I am using a GMutex and not a GStaticRecMutex and so it is my understanding that locking a GMutex twice in the same thread will just create a deadlock, not lock the mutex twice and proceed as in the case of the GStaticRecMutex. – bbazso Apr 07 '11 at 13:31
0

What was happening in my case was there was another thread that was calling g_cond_timed_wait function with the same mutex, but with the mutex unlocked. In this case, g_cond_timed_wait function unlocks a mutex that is not locked and leaves the mutex in an undefined state, which explains why I was seeing the behaviour explained in this question: the mutex being locked twice.

bbazso
  • 1,959
  • 6
  • 22
  • 30