先有利器,纔好幹活
- 通過pidin加參數 %B,可以看到當前進程的各個線程的STATE,例如:NANOSLEEP, SEM, JOIN,SEND,REPLY, RECEIVE, MUTEX, CONDVAR, 等等。
- QNX系統好一點的是,能夠標明線程被鎖住的mutex的地址,mutex隸屬的線程,被鎖住的次數。還能標明自線程REPLY、SEND等STATE下,所依賴的對方線程號。
本次問題出現在
MessageQueue類中的 pushMessage 和 handleMessage 兩個方法公用一把鎖來保護成員變量m_queue。一個MessageQueue的pushMessage方法會在調用線程, handleMessage會在MessageQueue自有線程中使用。當handleMessage中被客戶端業務代碼阻塞後,push就會被阻塞;
- 因此我的服務端的三條線程,通過兩個MessageQueue, 兩套鎖, 關聯起來。
- 客戶端服務端通過qnx msg passing的同步機制,關聯起來;
- 客戶端通過同樣的MessageQueue類, 兩條線程的一套鎖,關聯起來;
最後,死鎖來了:
- 客戶端MessageQueue中自有線程中的handleMessage調用業務函數鎖住;
- 導致客戶端MessageQueue pushMessage 方法鎖住;
- 導致服務端的MsgSend 阻塞在REPLY狀態;
- 導致服務端兩個 MessageQueue ,三個線程鎖起來。
解決方法
客戶端
handleMessageQueue中copy一份msg,把並把鎖及時釋放,原msg對象及時銷燬,msg副本在客戶端使用完後銷燬。確保客戶端卡主,不影響服務端。
服務端
業務和代碼都可控,不需要msg copy。