boost::mutex,pthread_mutex_destroy 失败 - 调试建议?
我们在静态类中有几个锁(boost::mutex),但是当程序退出时,pthread_mutex_destroy在互斥体的析构函数中失败(boost中有一个断言检查这一点)。
据我所知,pthread_mutex_destroy只会在两种情况下失败。
[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.
当我在 GDB 中运行并打印锁时,我看到它已解锁。 不幸的是我在 GDB 中打印 errno 时遇到问题。
#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}
现在我正在写这篇文章,__nusers 和 __size 的值看起来很奇怪。这可能暗示锁无效,但我知道锁在某些时候是有效的(我将 boost::mutex 包装在 Lock 类中,在构造函数、析构函数和锁中打印了 this(0x847840) 的值/解锁功能。
任何有关如何调试的帮助将不胜感激
。 Locks 类继承自 boost::mutex,并导出作用域锁(从内存):
lock_type::scoped_lock getScopedLock() {
return lock_type::scoped_lock( *this );
}
我还尝试将锁添加为成员,而不是继承它,行为没有任何变化。 我不认为 getScopedLock 函数会引入任何问题(作用域锁返回 y 值,但由于 RVO 而没有创建副本),但认为它值得一提。 它的使用如下(我们使用的是c++0x):
auto lock = lock_.getScopedLock();
完整的stracktrace:
(gdb) where
#0 0x00007ffff559da75 in *__GI_raise (sig=<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
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=<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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您在没有先锁定互斥体的情况下
解锁
互斥体时,通常会出现此错误。我的猜测是,您在某个地方使用
lock
和unlock
成员而不是RAII
,并且您丢失了对
lock
的调用。请注意,大多数时候您不应该调用
lock
和unlock
成员。使用scoped_lock
来为您调用函数。另外,您提到您是从
boost::mutex
继承的。这可能会导致问题,因为boost::mutex
没有虚拟析构函数,因此最好不要这样做。You typically get this error when you
unlock
your mutex without locking it first.My guess is that somewhere you are using
lock
andunlock
members rather thanRAII
,and that you have lost a call to
lock
.Note that most of the time you should not be calling the
lock
andunlock
members. Use thescoped_lock
which calls the functions for you.Also, you mention that you are inheriting from
boost::mutex
. This can cause problems becuaseboost::mutex
does not have a virtual destructor, so its best not to do that.好吧,结果有两个问题。
有一把锁,从来没有被使用过,但是当我停下来时,我确实调用了解锁。
显然我没有正确阅读文档,因为解锁有一个前提条件,即当前线程必须拥有锁。
谢谢汤姆让我看到这个。
第二个问题是,我在某个地方有一个作用域锁,我想在它超出作用域之前解锁它:
最初,这读作
lock_.unlock();
,所以我正在解锁互斥体,不通过作用域锁。@Tom,我不喜欢写
boost::mutex::scoped_lock l(lock_)
的原因是如果你写boost::mutex::scoped_lock l()
> 不会有任何错误。现在,我看到的唯一危险是有人编写
lock_.getScopedLock()
而不将其存储在变量中,我想当其他人开始接触代码时,我们只需定义一个宏来获取作用域锁(是的,我们可以对没有 getScopedLock 的变体执行相同的操作;))。无论如何,我不再从
boost::mutex
继承,而是将其保留为成员。你是对的,我们不应该冒险继承它。@丹尼尔,
使用 -lpthread 编译没有帮助,我现在没有时间查看该特定问题,因为我不需要它,但无论如何还是感谢您的建议。
@萨姆,
我确实在 valgrind 中运行,但它没有显示锁定问题的有趣输出。
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:
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 writeboost::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.