工作過程中遇到一個比較奇特的bug,在這裡記錄一下。
問題表現
原先有一部分程式能夠正常執行,但是執行了幾次錯誤的程式(會非正常退出,比如因為段錯誤等原因)之後,原先能夠正常執行的程式就沒法正常執行了,報錯顯示在獲取訊號量的過程中出錯了,進一步導致了應用初始化的過程失敗。但是在重啟後這個問題又會解決(遇事不決,重啟一下哈哈哈)
猜測原因
一開始懷疑是多執行緒訪問訊號量導致,但是這為什麼會導致之前有效的程式失效呢?而且重啟之後應該也沒法解決這個問題。思考無果之後選擇換一個思路。錯誤程式的程式碼中在非正常退出之前會執行一個申請訊號量的操作,但是在段錯誤發生之後才會執行釋放訊號量的操作,那麼有沒有可能是訊號量沒有釋放導致的?
檢查
使用以下指令,檢視一下系統當前的訊號量(目前是能正常跑的)
ipcs -s
也可以加上wc -l直接統計一下數量即可
ipcs -s | wc -l
發現居然有60+個訊號量集。查閱資料發現可以透過以下指令檢視系統最大訊號量集的數量,發現只有128
cat /proc/sys/kernel/sem
嘗試執行一次會發生段錯誤的部分程式碼,發現訊號量在程序結束後增加了6個,並且不會減少。
查閱資料發現,因為程式碼中建立的是非匿名訊號量,在程序結束之後,如果沒有主動將其釋放,該訊號量也不會自動的被作業系統釋放,因為作業系統也不知道它到底會不會被其他的程序所使用。當訊號量達到限制數量限制之後,就沒法正常的申請新的訊號量,導致程式執行失敗(未驗證)
解決方案
註冊訊號處理函式,在程式非正常退出時執行釋放訊號量的操作即可。