2011-08-23 96 views
1

我们在静态类中有几个锁(boost :: mutex),但是当程序退出时,pthread_mutex_destroy在互斥体的析构函数中失败(有一个断言在boost中检查它)。boost :: mutex,pthread_mutex_destroy失败 - 调试建议?

据我所知,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) /解锁功能

任何帮助就如何调试这将不胜感激

编辑 锁类自boost ::互斥继承,并导出一个scopedlock(从内存中):

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 
+0

如果你显示代码会有帮助(例如'Locks.h'中发生了什么) – Tom

+1

发布的代码很少,这是我发布此帖的原因之一,因为我不知道在成千上万行代码中寻找问题。所以很不幸,我也无法制作一个小型测试用例。我甚至不知道哪几个锁正在破坏(我可以通过打印所有锁的地址来初始化它们).Locks类所做的所有工作都是从boost :: mutex atm继承的,它的确如此别的。 – thelamb

+0

@thelamb如果您不能发布复制器,请在valgrind下运行您的代码。 –

回答

3

你通常得到这个错误,当您unlock你不互斥锁首先它。

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

我的猜测是某处你正在使用lockunlock成员,而不是RAII, 和你已经失去了lock通话。

请注意,大多数情况下,您不应该致电lockunlock成员。使用为您调用功能的scoped_lock

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

此外,你提到你是从boost::mutex继承。这可能会导致问题,因为boost::mutex没有虚拟析构函数,所以最好不要这样做。

+0

谢谢您的回复,我会检查我们对锁和解锁的使用情况。在大多数情况下,我们已经使用了scoped_lock。你对继承是不安全的权利,但我已经检查过,如果我修改Lock来保持互斥锁作为成员并导出锁定/解锁功能,问题仍然存在。我将再次执行此操作并保留一个变量,以检查是否首先调用解锁并且状态仍处于解锁状态。我忘了提及Lock的一件事,请参阅我的编辑帖子 – thelamb

+0

以了解您对getScopedLock的关注:我应该提及我们使用的是C++ 0x。 Scoped锁是可移动的。但由于这里不涉及移动或复制,所以不应该有任何问题(我并不过分担心它不适用于其他编译器)。 – thelamb

3

好的结果有两个问题。 有一个锁,从来没有被使用过,但当停止时,我确实打电话解锁。 很明显,我没有正确地阅读文档,因为解锁前的前提条件是当前线程必须拥有锁定。 谢谢汤姆让我看到这一点。

的第二个问题是,什么地方我有一个范围的锁,我想解开它,它超出范围之前:

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

原来,这个阅读lock_.unlock();,所以我解锁互斥,不通过范围锁定。

@汤姆,我不喜欢写作boost::mutex::scoped_lock l(lock_)的原因是,如果你写boost::mutex::scoped_lock l()不会有任何错误。 现在,我看到的唯一危险是有人在没有将其存储在变量中的情况下编写lock_.getScopedLock(),我想当其他人开始触摸代码时,我们只需定义一个宏来获取作用域锁定(是的,我们可以做同样的事情对于没有getScopedLock;)的变体)。 无论如何,我不是从boost::mutex继承,而是保持它作为一个成员。你是对的,我们不应该冒险继承它。

@Daniel, 与-lpthread没有帮助编译,我没有时间去看看那个特定问题的时刻,因为我并不需要它,但感谢你的建议呢。

@Sam, 我的确在valgrind中运行过,但是它并没有显示锁定问题的有趣输出。