我一直在向Android移植一个跨平台的C引擎,并注意到在调用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以进行错误检查和递归互斥,但这并不重要.我甚至没有得到错误或日志输出,所以这意味着我的互斥代码很好,或者没有显示错误/日志.操作系统究竟如何通知您有关互斥锁使用情况的错误?
引擎大量使用静态变量,包括互斥锁.我看不出怎么样,但这是一个问题吗?我对此表示怀疑,因为我修改了许多要在堆上分配的互斥锁,并且发生了相同的行为.但那可能是因为我错过了一些静态互斥锁.我可能在这里抓住稻草.
我读过几篇参考文献,包括
解决方法:
“错误检查”互斥锁将检查一些事情(例如尝试递归使用非递归互斥锁)但没什么了不起的.
您说“实际代码会检查所有返回值”,因此如果任何pthread调用返回非零值,您的代码可能会爆炸. (不确定为什么你的pthread_mutex_destroy需要两个args;假设copy和amp; paste错误.)
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的输出,可以让你知道锁定互斥锁的线程是否仍然存在.
标签:android,mutex,android-ndk,pthreads
来源: https://codeday.me/bug/20190709/1412278.html