pthread_mutex_destroy: 为什么返回EBUSY错误码?

4
我在第三方库的“关闭”代码中进行了一些代码步进,向我们的应用程序发送 SIGQUIT,这将关闭第三方对象。但是出现了问题,该库正在调用 pthread_mutex_destroy 时失败,并返回错误码 16: EBUSY。文档说当“实现检测到在其他线程中锁定或引用(例如,在 pthread_cond_timedwait() 或 pthread_cond_wait() 中使用)mutex 引用的对象被销毁的尝试时,会发生此错误”。 我已经在 pthread_mutex_destroy() 调用的位置设置了断点。
a)我不相信它被锁定了,因为互斥锁的状态看起来像这样: $6 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 4294967293, __kind = 0, __spins = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = '\000' "\375, \377\377\377", '\000', __align = 0}
我的猜测是 __lock = 0 意味着“未锁定”。但是,我不知道 __nusers 究竟代表什么。
b) 我没有看到任何 pthread_cond_wait() 或 pthread_cond_timedwait() 的证据。我得到了所有正在运行的线程的回溯,并且没有一个线程在等待该互斥量。
这里可能出了什么问题?

1
你没有设置一个信号处理线程,而是让实现自己选择了吧? - WhozCraig
是的,我们确实有一个信号处理线程。然而我并不明白为什么我们的信号处理线程会提示所有这些关闭逻辑的发生。这是否意味着我为什么会收到EBUSY错误? - vmayer
我之所以问这个问题,是因为有可能有人正在等待与该互斥锁相关的条件变量。你需要以优雅的方式将互斥锁与上述所有内容分离。过去,我通常通过使用带有关闭谓词的条件变量信号广播来完成此操作,然后让信号线程终止(当然是优雅地终止,而不是直接退出线程)。其余的就像多米诺骨牌一样倒下了。无论这对你的设备或应用程序是否合适(甚至是否合适)都是另一回事。 - WhozCraig
如果有人在等待与该互斥锁结婚的condvar,那么其中一个线程的回溯应该在堆栈顶部显示这一点,对吧?其他等待condvars的线程都与其他互斥锁结婚了。请让我知道我是否正确地理解了您的意思,以及我所说的是否有意义,谢谢。 - vmayer
1
glibc的pthread代码相当复杂,但它看起来pthread_mutex_destroy()__nusers成员非零时确实返回EBUSY。不过,你的互斥锁状态似乎无效(需要声明的是,pthread代码相当复杂,所以我可能在这方面出错的概率大于0)。有没有可能你的关闭代码的某个部分在销毁调用完成之前破坏了互斥锁或释放了互斥锁所在的内存块? - Michael Burr
1个回答

5
显然,你的问题与__nusers成员有关。我猜想,在某个地方你解锁了已经解锁的互斥锁。

是的,我确实有证据表明互斥锁被解锁了两次(我正在打印相关语句)。我想过提到它,但认为它是无害的(抱歉)。你是说每次发生unlock()时,__nusers成员都会减少,但是由于__nusers是带符号的,因此看起来像4294967293?然后pthread_mutex_destroy()返回EBUSY,因为__nusers不为零(就像Michael Burr上面提到的那样)? - vmayer
1
__nusers本身是无符号的,但是pthread_mutex_unlock会在早上第一件事情就盲目地将其减少(http://code.metager.de/source/xref/gnu/glibc/nptl/pthread_mutex_unlock.c),所以是的,它的值会回绕到0xfff...。 - oakad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接