开发者

boost::mutex, pthread_mutex_destroy failed - debug suggestions?

We have several locks (boost::mutex) in static classes, but when the program exits, pthread_mutex_destroy fails in the destructor of the mutex (there is an assertion checking this in boost).

As far as I know, pthread_mutex_destroy will only fail in two cases.

[EBUSY]  The implementation has detected an attempt to destroy the object referenced by mutex   while it is locked or referenced (for example, while being used in a pthread_cond_timedwait() or pthread_cond_wait()) by another thread.
[EINVAL] The value specified by mutex is invalid.

When I run in GDB and I print the lock I see that it is unlocked. Unfortunately I'm having trouble printing errno in GDB.

#3  0x000000000044a2c6 in ~mutex (this=0x847840, __in_chrg=<value optimized out>) at /usr/include/boost/thread/pthread/mutex.hpp:47
47              BOOST_VERIFY(!pthread_mutex_destroy(&m));
(gdb) p m
$1 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 4294967294, __kind = 0, __spins = 0, __list = {__prev = 0x0, 
      __next = 0x0}}, __size = '\000' <repeats 12 times>"\376, \377\377\377", '\000' <repeats 23 times>, __align = 0}

Now that I am writing this post the value of __nusers and __size look strange. This could hint to the lock being invalid, but I know that the lock was valid at some point (I wrap the boost::mutex in a Lock class, where I printed the value of this(0x847840) in the constructor, destructor and lock/unlock functions.

Any help as to how to debug this would be greatly appreciated.

Edit The Locks class inherits from boost::mutex, and exports a scopedlock (from memory):

lock_type::scoped_lock getScopedLock() {
  return lock_type::scoped_lock( *this );
}

I've also tried to add the lock as a member, instead of inheriting from it, with no change in behavior. I do not think that the getScopedLock function could introduce any problems(the scoped lock is returned y value, but a copy is not made because of RVO), but thought it could be worth mentioning. It is used as follows (we are using c++0x):

auto lock = lock_.getScopedLock();

The complete stracktrace:

(gdb) where
#0  0x00007ffff559da75 in *__GI_raise (sig=&l开发者_JS百科t;value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007ffff55a15c0 in *__GI_abort () at abort.c:92
#2  0x00007ffff5596941 in *__GI___assert_fail (assertion=0x55851c "!pthread_mutex_destroy(&m)", file=<value optimized out>, line=47, 
    function=0x5595a0 "boost::mutex::~mutex()") at assert.c:81
#3  0x000000000044a2c6 in ~mutex (this=0x847840, __in_chrg=<value optimized out>) at /usr/include/boost/thread/pthread/mutex.hpp:47
#4  0x000000000044d923 in ~Lock (this=0x847840, __in_chrg=<value optimized out>) at include/Locks.h:43
#5  0x00007ffff55a3262 in __run_exit_handlers (status=0) at exit.c:78
#6  *__GI_exit (status=0) at exit.c:100
#7  0x00000000004ea9a6 in start () at src/main.cc:191
#8  0x00000000004de5aa in main (argc=1, argv=0x7fffffffe7b8) at src/main.cc:90


You typically get this error when you unlock your mutex without locking it first.

  boost::mutex m;
  m.unlock();

My guess is that somewhere you are using lock and unlock members rather than RAII, and that you have lost a call to lock.

Note that most of the time you should not be calling the lock and unlock members. Use the scoped_lock which calls the functions for you.

struct s
{
  void foo()
  {
    boost::mutex::scoped_lock l(m_mutex);
    //do something
  }
  private: 
    boost::mutex m_mutex;
};

Also, you mention that you are inheriting from boost::mutex. This can cause problems becuase boost::mutex does not have a virtual destructor, so its best not to do that.


Ok turns out there were two problems. There was one lock, which never got used but when stopping I did call unlock. Obviously I didn't read the documentation correctly, as there is a precondition on unlock that the current thread must own lock. Thank you Tom for getting me to see this.

The second problem was that somewhere I have a scoped lock, and I want to unlock it before it goes out of scope:

auto lock = lock_.getScopedLock();
if( something )
   lock.unlock();

Originally, this read lock_.unlock();, so I was unlocking the mutex, not via the scoped lock.

@Tom, the reason I don't like writing boost::mutex::scoped_lock l(lock_) is that if you write boost::mutex::scoped_lock l() there will be no errors whatsoever. Now, the only danger I see is that someone writes lock_.getScopedLock() without storing it in a variable, I guess when someone else starts touching the code we'd just define a macro for getting the scoped lock (yes yes, we could do the same for the variant without getScopedLock ;)). In any case, I'm not inheriting from boost::mutex anymore, but instead keeping it as a member. You are right that we should not risk inheriting from it.

@Daniel, Compiling with -lpthread did not help, I don't have time to look at that particular problem at the moment, as I don't need it, but thank you for your suggestion anyway.

@Sam, I did run in valgrind, but it showed no interesting output to the lock problem.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜