2012-12-07 155 views
4

我一直在向Android移植一個跨平臺的C++引擎,並且注意到在調用pthread_mutex_lock時它會莫名其妙地(並且不一致)阻塞。這個引擎已經在多個平臺上工作了很多年,並且有問題的代碼在多年內沒有改變,所以我懷疑它是死鎖或其他錯誤的代碼。它必須是我的端口到Android ..android NDK互斥鎖定

到目前爲止有幾個地方在代碼中阻止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

+0

使用pthread_mutex_trylock()並檢查返回值。如果不是零,則檢查errno變量值。 – keltar

回答

1

「錯誤檢查」互斥體將檢查幾件事情(如試圖遞歸使用非遞歸互斥體),但沒有什麼特別的。

你說「真正的代碼檢查所有返回值」,所以假設你的代碼爆炸,如果任何pthread調用返回一個非零值。 (不知道爲什麼你的pthread_mutex_destroy有兩個參數;假設複製&粘貼錯誤。)

的並行線程的代碼被廣泛的Android內使用,並沒有已知的掛斷,所以這個問題是不可能在並行線程實現本身。

當前實現互斥的適合在32位,因此,如果您打印*(pthread_mutex_t* mut)作爲一個整數,你應該能夠找出什麼狀態,它是在(在技術上,什麼狀態時,它在過去的某個時間) 。在仿生/ libc中/仿生/ 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的輸出,會讓你知道鎖定互斥鎖的線程是否仍然存在。

+0

感謝您的確切答覆。事實證明,有幾個互斥量正在遞歸使用(默認情況下,我將所有互斥量設置爲「快速」)。考慮到多線程代碼的不可預測性,在設置它們進行錯誤檢查時,我沒有捕獲它的前幾次運行,所以我不認爲這是問題所在。然後我設置它們遞歸,當然這個問題完全消失了(我不知道我偶然發現了這個解決方案)。在某些時候,我將它們重新設置爲錯誤檢查,並確實導致了錯誤的使用情況。這個故事的道德是將一個巨大的代碼庫移植到一個新的平臺上可能會很棘手:) – foo64

+0

現在我還有另一個問題,這是一個互斥鎖在被鎖定時被破壞。據推測,問題一直存在很長時間,但從來沒有找到由於過度寬容的API(我在看你,DeleteCriticalSection!) – foo64