利用glibc中鎖結構的資訊解決死鎖問題

2021-09-06 11:14:44 字數 1437 閱讀 1017

首先非常感謝老丁和老李同學的幫助,沒有他們這個問題估計又得搞很久。遇見這個問題,真是頭疼。不熟悉**、不熟悉流程,但是領導還是把活給排下來了(實在不解),只能硬著頭皮找了。

問題是這樣的,cache伺服器中有乙個儲存物件的雜湊表,每次訪問雜湊表時都要獲取hash_rwlock讀寫鎖,現在程序在獲取讀鎖時死鎖。使用gdb進入3個worker程序,發現死鎖的位置都一樣,都是在獲取hash_rwlock讀鎖時阻塞住了。遇見這樣的問題,加上對**不熟,真是各種犯二。因為reload的關係,程序其實總共有9個,但是3個是一組的,所以只看了其中的一組,沒有全部檢視,如果全部檢視的話,估計可以更早發現問題。

找了glibc的原始碼來看,發現pthread_rwlock_t結構的成員竟然完全沒有注釋,只好去看加鎖、解鎖的函式。在獲取讀鎖時,只有在__writer成員為0並且__nr_writers_queued為0,即沒有程序獲取寫鎖或等待獲取寫鎖時,才會獲取鎖成功。獲取讀鎖成功後,會將__nr_readers成員加1.這麼看來的話,__nr_readers儲存的是當前獲取讀鎖的程序或執行緒數量。在獲取寫鎖時,只有在__writer成員為0,並且__nr_readers為0,即沒有程序或執行緒獲取寫鎖或讀鎖時,才會獲取寫鎖成功。獲取寫鎖成功後,會將__writer成員設定為執行緒id(如果是單程序,則為程序id),如下所示:

rwlock->__data.__writer = thread_getmem (thread_self, tid);
最初沒有注意到這行**,自己寫了乙個獲取寫鎖的測試程式,然後用gdb列印出來的。這個方法雖然笨,沒有思路的時候或許著急的時候,也是不錯的。

有了這些資訊,再看上面的圖,可以發現很多資訊。__nr_readers為0,表示沒有程序或執行緒獲取hash_rwlock的讀鎖;__writer為12959,說明程序id為12959的程序正在獲取hash_rwlock的寫鎖。

現在一下子找到了方向,立馬gdb進入12959程序,發現它阻塞在獲取另乙個程序鎖process_lock(型別為pthread_mutex_t),列印process_lock,如下圖所示:

pthread_mutex_t型別中的__owner中儲存的是獲取當前互斥鎖的程序或執行緒id。找到了互斥鎖的持有者,再gdb進入12960程序,發現阻塞在獲取hash_rwlock讀鎖的位置。

至此問題就很明了了,典型的死鎖。a程序獲取了鎖m,然後去獲取另乙個鎖n,而b程序獲取了鎖n,然後去獲取了另乙個鎖m,交叉去獲取鎖,都阻塞了,都在等對方釋放鎖。出現這種問題的原因,要麼是流程設計有問題,要麼就是在某個地方獲取鎖了之後沒有正確釋放。我們的這個問題就屬於後者,在乙個函式中在失敗的時候沒有釋放鎖就直接返回了......

利用 Sql 中檢視表結構資訊

1 select 表名 case when a.colorder 1 then d.name else end,表說明 case when a.colorder 1 then isnull f.value,else end,字段序號 a.colorder,欄位名 a.name,標識 case whe...

利用巨集來求出結構體成員的一些資訊

1 define offsetof type,member size t type 0 member 巨集功能 獲得乙個結構體變數成員在此結構體中的偏移量。1.type 0 將零轉型為type型別指標 2.type 0 member 訪問結構中的資料成員 3.type 0 member 取出資料成員...

利用oracle中的序列巧解併發流水號問題

問題背景分析 在行式填報表中,可以通過使用流水號來作為自增長型主鍵進行資料的更新。在這種情況下,多使用者併發批量新增若干資料的時候,就可能會產生由於主鍵衝突而導致的併發插入資料失敗。原因是潤幹自帶流水號是根據資料表的主鍵id欄位的max 值為基礎 通過自加或自減實現遞增或遞減的流水號,這種流水號的遞...