Android NDK互斥锁定

5
我一直在将跨平台的C++引擎移植到Android上,并注意到在调用pthread_mutex_lock时会出现阻塞,而且这种情况不可预知且不一致。该引擎已经在多个平台上工作了多年,问题代码多年未更改,因此我怀疑这不是死锁或其他有缺陷的代码。很可能是我对Android的移植问题。
到目前为止,在代码中有几个地方会阻塞在pthread_mutex_lock上。这也不能完全重现。当它挂起时,LogCat中没有可疑的输出。
我修改了互斥体代码如下(为简洁起见进行编辑...真实代码检查所有返回值):
void MutexCreate( Mutex* m )
{
#ifdef WINDOWS
    InitializeCriticalSection( m );
#else ANDROID
    pthread_mutex_init( m, NULL );
#endif
}


void MutexDestroy( Mutex* m )
{
#ifdef WINDOWS
    DeleteCriticalSection( m );
#else ANDROID
    pthread_mutex_destroy( m, NULL );
#endif
}

void MutexLock( Mutex* m )
{
#ifdef WINDOWS
    EnterCriticalSection( m );
#else ANDROID
    pthread_mutex_lock( m );
#endif
}

void MutexUnlock( Mutex* m )
{
#ifdef WINDOWS
    LeaveCriticalSection( m );
#else ANDROID
    pthread_mutex_unlock( m );
#endif
}

我尝试修改MutexCreate以实现错误检查和递归互斥锁,但似乎没有起到作用。我甚至没有收到任何错误或日志输出,这意味着我的互斥锁代码没问题,或者错误/日志没有被显示出来。操作系统如何通知您使用了不良的互斥锁?

引擎大量使用静态变量,包括互斥锁。我看不出来有什么问题,但是会有问题吗?我怀疑不会,因为我将许多互斥锁修改为在堆上分配,但是发生了相同的行为。但这可能是因为我错过了某些静态互斥锁。我可能在抓住稻草。

我阅读了几个参考资料,包括:

http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_mutex_init.html

http://www.embedded-linux.co.uk/tutorial/mutex_mutandis

http://linux.die.net/man/3/pthread_mutex_init

Android NDK Mutex

Android NDK problem pthread_mutex_unlock issue


使用pthread_mutex_trylock()并检查返回值。如果不是零,请检查errno变量的值。 - keltar
1个回答

2
“errorcheck”互斥锁将检查一些内容(例如尝试递归使用非递归互斥锁),但没有什么特别的。
你说“真正的代码检查所有返回值”,因此假设你的代码会崩溃,如果任何pthread调用返回非零值。(不确定为什么你的pthread_mutex_destroy需要两个参数;假设是复制和粘贴错误。) pthread代码在Android内被广泛使用,并且没有已知的挂起问题,因此问题不太可能在pthread实现本身中。
互斥锁的当前实现适合32位,因此,如果您将 *(pthread_mutex_t * mut)打印为整数,则应该能够确定它处于什么状态(技术上讲,它在过去的某个时刻处于什么状态)。 在bionic / libc / bionic / pthread.c中的定义为:
/* a mutex is implemented as a 32-bit integer holding the following fields
 *
 * bits:     name     description
 * 31-16     tid      owner thread's kernel id (recursive and errorcheck only)
 * 15-14     type     mutex type
 * 13        shared   process-shared flag
 * 12-2      counter  counter of recursive mutexes
 * 1-0       state    lock state (0, 1 or 2)
 */

"快速"互斥锁的类型为0,不设置tid字段。实际上,通用互斥锁的值为0(未持有),1(已持有)或2(已持有,存在争用)。如果您看到值不是其中之一的快速互斥锁,则很可能是其他操作干扰了它。
这也意味着,如果您配置程序使用递归互斥锁,可以通过获取位来查看哪个线程持有互斥锁(通过在trylock指示即将停顿时打印互斥锁值,或在挂起进程上使用gdb转储状态)。除此之外,ps -t的输出将让您知道锁定互斥锁的线程是否仍然存在。

感谢您提供的可靠答案。事实证明,有几个互斥锁被递归使用了(我默认将所有互斥锁设置为“快速”)。由于多线程代码的不可预测性,当将它们设置为错误检查时,我在前几次运行中没有发现问题,因此我认为那不是问题所在。然后我将它们设置为递归,当然问题完全消失了(我不知道我已经偶然找到了解决方案)。最终我将它们设置回错误检查,并发现了错误的使用方式。故事的寓意是将一个庞大的代码库移植到新平台可能会很棘手 :) - foo64
现在我有另一个问题,那就是互斥锁在被锁定时被销毁。可能由于过于宽容的API(我看着你,DeleteCriticalSection!),这个问题已经存在很长时间,但从未被发现。 - foo64

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