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 互斥锁

Android NDK 问题 pthread_mutex_unlock 问题

4

1 回答 1

2

“错误检查”互斥锁将检查几件事(例如尝试递归地使用非递归互斥锁),但没有什么特别的。

您说“真实代码检查所有返回值”,因此如果任何 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,您将知道锁定互斥锁的线程是否仍然存在。

于 2012-12-11T00:46:51.473 回答