乙個執行緒死鎖問題的分析

2021-06-02 10:14:16 字數 1918 閱讀 3496

客戶報過來乙個問題,伺服器執行一周左右就會停止響應,有時候甚至兩天就不響應了,併發使用者量並不大,重啟服務後又工作正常。每當遇到這種問題時就有點兒棘手。一是這種問題的復現條件不好確定,另一方面,即使確定了條件,對於多執行緒的服務程式,也不好除錯。我遇到過的這種問題,大部分是靠讀**分析出來乙個可能的原因列表,然後一一驗證,最終找到真正的問題所在。

首先拿到服務執行日誌發現沒有任何錯誤訊息。

抓到trace發現,每個執行緒都沒有報錯誤,但是到了某一時刻就全部停止工作了。首先想到會不會和時間有關係,詢問客戶,停止響應的時間並不固定。

拿到服務停止時的各個執行緒的呼叫棧,發現所有的工作執行緒都停留在pthread_cond_wait上,看來執行緒之間同步處理有問題。

先嘗試復現一下,看看和特定的資料有沒有關係。同事寫了個多執行緒的客戶端,併發查詢伺服器,問題很快就出現了,這也暴漏了我們在測試方面的不足。

開始分析**,這段**其實有很多處理,非常複雜,寫了個簡單的示例**:

#define read_lock 1

int get_data_from_cache(int index, entrydata** entry)

int release_lock_for_entry(entrydata* entry, type)

--ed->locked_state;

break; }

} }pthread_cond_broadcast(global_data->cond_var);

pthread_mutex_unlock (global_data->lock_var);

return 0; }

int thread_main()

這段**先從cache中把資料取出來,同時加鎖(locked_state),進行處理後再釋放鎖。pthread_cond_wait使執行緒進入等待狀態,當有另乙個執行緒呼叫pthread_cond_signal或者pthread_cond_broadcast時,等待的執行緒才會被啟用。

**中對應的pthread_cond_broadcast是有的,而且正常流程下會執行到,沒有問題。

然後看什麼條件下會進入pthread_cond_wait,當locked_state不等於read_lock時,也就是當有多個執行緒同時讀取同一條entry時。但是第乙個執行緒會呼叫pthread_cond_broadcast,觸發第二個執行緒執行,然後第二個執行緒呼叫pthread_cond_broadcast,觸發第三個執行緒執行,如此反覆,不會所有的執行緒都等待。

如果第乙個執行緒也進入等待狀態,那麼所有的執行緒就都只能等待,伺服器就不能響應了。有什麼原因導致以乙個執行緒直接進入等待狀態呢?也是locked_state不等於read_lock時。這是第乙個執行緒,而且對於locked_state的修改都有mutex封裝。不會同時又多個執行緒更改locked_state.

多看幾遍**發現,修改locked_state(即

get_data_from_cache)和判斷locked_state(即

release_lock_for_entry)雖然都在mutex中,但是它們在不同的函式裡,兩個函式之間還有一塊**(即

// process the data部分)不在mutex的保護之中。設想這樣一種情況,當第乙個執行緒取出entry並修改locked_state後,開始處理資料,這時第二個執行緒讀取資料,同時修改了locked_state,此時locked_state不再是read_lock了,然後第乙個執行緒處理完畢開始釋放鎖,由於locked_state不是read_lock,所以第乙個執行緒開始進入pthread_cond_wait等待。可是第乙個執行緒等待了,其他的工作執行緒就都等待了。沒有執行緒處理新的請求了,伺服器也就不響應了。

找到了問題原因,就好修改了。

有乙個啟發:服務停止時的各個執行緒的呼叫棧,發現所有的工作執行緒都停留在pthread_cond_wait上

學習這種除錯方法。

乙個死鎖問題

表結構 create table test id bigint 20 unsigned not null auto increment comment 自增id a varchar 100 not null default comment 唯一健 b bigint 20 unsigned not n...

乙個模擬死鎖的多執行緒

package org.kevinlifeng public class testdeadlock implements runnable catch interruptedexception e t1嘗試鎖o2 可o2 已經被t2 給鎖住了還沒釋放,一直等待 synchronized o2 到了這...

乙個MySQL死鎖問題的反思

很早之前我寫過幾篇關於mysql死鎖的分析,比如 但是感覺不過癮,而且分析的都是一些特定的場景,好像還缺少一些舉一反三的感覺,所以今天就補上這一波。mysql裡的鎖相容列表大體是這樣的關係,如果第一次看會有些暈,感覺抓不住重點,其實有一點小技巧。首先innodb實現了兩種類似的行鎖,即s 共享鎖 和...