Pthread互斥锁断言错误

49

我在一个基于Linux(ARM)的通信应用程序中时不时地遇到以下错误:

pthread_mutex_lock.c:82: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.

在谷歌上搜索这个错误会出现很多参考资料,但似乎没有什么与我情况相关的信息。我想知道是否有人可以给我一些解决这个错误的思路。有人知道这种断言错误的常见原因吗?

提前致谢。


3
在排除了所有其他可能性之后,我决定投资一些RTFM。看起来我一直在以一种官方不支持的方式使用互斥锁。当线程正在等待某些外部刺激时,它会等待其互斥锁。当互斥锁被释放时,线程会重新启动,总是来自另一个线程。因此,释放线程永远不是互斥锁所有者。我改变了实现方式,使用条件变量。我还不知道这是否是我遇到问题的原因。我已经(误)使用这种方式使用互斥锁多年了,直到现在都没有任何问题。 - Dave Causey
4
“pthread_mutex”(以及一般的mutex)不是被记录在文档中必须由相同的线程解锁吗?在其他平台上它可以工作的事实是特定于实现而不是可移植的。 - ephemient
我认为这就是我在上面的评论中所说的。我的实现误用了互斥锁,所以我进行了更改,以正确使用条件变量。现在仅需确认这是否真的是间歇性断言背后的原因。 - Dave Causey
有时候当我的互斥锁没有正确初始化时,我会遇到相同的错误 --> 使用pthread_mutex_init。 - Chris Maes
8个回答

37

四天内稳如磐石。我宣布取得了胜利。答案是“愚蠢的用户错误”(请参见上面的评论)。互斥锁只应由锁定它的线程解锁。感谢您一直以来的支持。


5
你的解决方案只适用于解锁,是吗?当我试图锁定它时也出现了同样的错误。 - User

12

简短版: 确保不要锁定已被销毁/未初始化的互斥量。

虽然问题已经解决,但我想分享我的问题以防其他人遇到和我类似的问题。

请注意,断言出现在__pthread_mutex_lock而不是解锁中。对我来说,这意味着大多数遇到此问题的其他人并不是在不同的线程中解锁了互斥量,而是锁定了一个已经被销毁的互斥量。

对于我而言,我有一个类(我们称之为Foo),它在某个其他类(我们称之为Bar)中注册了一个静态回调函数。该回调会传递一个对Foo的引用,并且会偶尔锁定/解锁Foo的成员互斥量。

Foo实例被销毁后,Bar实例仍在使用该回调函数时出现了此问题。该回调函数将引用传递给一个不存在的对象,因此在垃圾内存上调用 __pthread_mutex_lock。

请注意,我使用的是C++11的std::mutexstd::lock_guard<std::mutex>,但由于我在Linux上,所以问题完全相同。


1
此外,当我两次解锁相同的锁时,发生了这种情况。断言错误发生在我下一次尝试获取锁时,这使得它有点难以找到。 - HashFail

4
我曾经面临同样的问题,谷歌把我带到了这里。我的程序问题在于,在某些情况下,在锁定之前没有初始化互斥量。
虽然接受答案中的语句是合法的,但我认为它不是此失败断言的原因。因为错误报告在pthread_mutex_lock(而不是解锁)上。
此外,像往常一样,程序员源代码中的错误比编译器更有可能。

2

@mark 你是对的。我改变了我的答案。 - yyFred
@yyFred,你这里还有一个小错别字。我猜应该是要写成“unique”而不是“unqiue”。只是提醒一下。祝你有美好的一天! - Andre

1
我遇到了同样的问题。在我的情况下,我正在线程内使用ODBC连接Vertica数据库,将以下设置添加到/etc/odbcinst.ini中解决了我的问题。到目前为止没有出现异常。
[ODBC]
Threading = 1

致谢:hynek

1
我刚刚经历了这个问题并认为可能有助于他人。在我的情况下,问题发生在一个非常简单的方法中,它锁定互斥量,检查共享变量,然后返回。该方法是基类的一个重写,创建了一个工作线程。
在这种情况下的问题在于,基类在构造函数中创建线程。然后线程开始执行,并调用派生类实现的方法。不幸的是,派生类尚未完成构造,而派生类中的互斥量具有未初始化的数据作为互斥量所有者。这使它看起来已经被锁住了,但实际上没有。
解决方案非常简单。在基类中添加一个名为StartThread()的受保护方法。这需要从派生类的构造函数中调用,而不是从基类中调用。

1

我做了一些简单的谷歌搜索,发现这个问题通常是由编译器错误优化引起的。这里有一个很好的总结。你可以查看汇编输出以确定gcc是否产生了正确的代码。

或者你可能会意外地覆盖了pthread库使用的内存......这类问题不太容易发现。


我曾经遇到过编译器错误优化的问题,但在这种情况下似乎不是问题: assert (mutex->__data.__owner == 0); 154: e5953008 ldr r3, [r5, #8] 158: e3530000 cmp r3, #0 ; 0x0 15c: 1a0001a0 bne 7e4 <__pthread_mutex_lock+0x7e4> - Dave Causey

0
在 /etc/odbcinst.ini 文件中添加 Threading=0 可以解决此问题。

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