我们在静态类中有几个锁(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类中,我在构造函数,析构函数和锁中打印了这个值(0x847840) /解锁功能。
非常感谢任何有关如何调试此方法的帮助。
修改 Locks类继承自boost :: mutex,并导出scopedlock(来自内存):
lock_type::scoped_lock getScopedLock() {
return lock_type::scoped_lock( *this );
}
我还尝试将锁添加为成员,而不是继承它,而不改变行为。 我不认为getScopedLock函数可能会引入任何问题(scoped lock返回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
答案 0 :(得分:3)
当你{m}注意你的互斥锁时,通常会出现此错误。
unlock
我的猜测是您正在使用 boost::mutex m;
m.unlock();
和lock
成员而不是unlock
,
并且您忘记了对RAII
的电话。
请注意,大部分时间您都不应该致电lock
和lock
成员。使用为您调用函数的unlock
。
scoped_lock
另外,您提到您继承自struct s
{
void foo()
{
boost::mutex::scoped_lock l(m_mutex);
//do something
}
private:
boost::mutex m_mutex;
};
。这可能会导致问题因为boost::mutex
没有虚拟析构函数,所以最好不要这样做。
答案 1 :(得分:3)
好的,原来有两个问题。 有一个锁,从来没有使用,但停止时,我确实打电话解锁。 显然我没有正确阅读文档,因为解锁时有一个先决条件,当前线程必须拥有锁。 谢谢汤姆让我看到这个。
第二个问题是在某个地方我有一个范围锁,我想在它超出范围之前将其解锁:
auto lock = lock_.getScopedLock();
if( something )
lock.unlock();
最初,这个读lock_.unlock();
,所以我解锁了互斥锁,而不是通过范围锁。
@Tom,我不喜欢写boost::mutex::scoped_lock l(lock_)
的原因是,如果你写boost::mutex::scoped_lock l()
,就不会有任何错误。
现在,我看到的唯一危险是有人写lock_.getScopedLock()
而不将其存储在变量中,我想当别人开始触摸代码时我们只是定义一个宏来获取范围锁(是的,我们可以对没有getScopedLock的变体做同样的事情;))。
无论如何,我不再继承boost::mutex
,而是将其保留为成员。你是对的,我们不应该冒险继承它。
@Daniel, 使用-lpthread进行编译没有帮助,我现在没有时间查看该特定问题,因为我不需要它,但无论如何,谢谢你的建议。
@Sam, 我确实在valgrind中运行,但它没有显示锁定问题的有趣输出。