經過多次調試,一位同事終於解決了這個問題。
內容提要
例外正被調用pthread_mutex_init()後55-65 升壓::互斥構造調用拋出因爲一個應用程序級別的派生類對象,具有一個boost ::互斥作爲成員變量,因爲基類析構函數是非虛擬的,所以沒有被完全破壞。這導致boost :: mutex-s的數量上升,直到拋出互斥異常。當正確調用派生類的析構函數時,互斥異常不再被拋出。
相關/有趣的事實沿途收集
(1)早期的理論提出了有系統過多的互斥和申請超過上同步的最大數量的某種未知的限制允許的對象(儘管QNX文檔明確指出這些對象的數量是無限的)。爲了驗證這一點,我們修改了的boost ::互斥類從:
class mutex
{
private:
. . .
public:
mutex()
{
. . .
}
~mutex()
{
. . .
}
}
到:
class mutex
{
private:
static int _nCount;
public:
mutex()
{
++_nCount;
. . .
}
~mutex()
{
. . .
--_nCount;
}
static int getCount()
{
return _nCount;
}
. . .
}
注意,使用的_nCount變量不同步(我們需要一個互斥對象這個!),但是調用應用程序中的調試boost :: mutex :: getCount()函數使我們確信,異常時的互斥量很低(平均55-65個活動互斥量)。
通過添加靜態訪問函數來監視最低級別的對象(例如Boost中的互斥體)的這種技術是調試粘性問題時需要考慮的一個好工具。(2)我們偶爾會收到一個ENOMEM異常,表明存在內存問題(「系統無法分配創建互斥鎖所需的資源」)。
(3)A FreeBSD site posting from three months ago是非常相似,我們的症狀:
我有麻煩,我似乎無法解決。我的程序 可重複創建和銷燬互斥鎖(顯然,它們在 之間使用它們)。在創建的第60個鎖附近,我總是獲得ENOMEM。我有 可用內存,很多。所有的鎖都會正確釋放。
不幸的是,這個線程並沒有將我們指向一個建設性的方向。 (4)當仔細研究應用程序的代碼時,發現了一個派生對象,它的基類析構函數是非虛的,從而泄漏了一些內存,這一突破來臨了。通過虛擬基類析構函數修復了內存泄漏並解決了互斥異常。
(5)即使在使基類的析構函數虛擬化之後,我們發現在使用QNX®Momentics Tool Suite編譯Blackberry 10時,並未調用派生類的析構函數。我們通過指定基本和派生的析構函數爲「虛擬」來「破解」此問題。只有這樣,派生的析構函數纔會被調用。這可能表明QNX編譯器的C++規範實現中存在錯誤,該規範明確指出虛擬傳播到派生類(Working Draft, Standard for Programming Language C++ (2012), page 250, footnote 9)。
編輯:請參閱this Stack Overflow post瞭解有關虛擬析構函數的QNX丟球的另一個示例。
'io_service'將在各種平臺上內部使用互斥鎖來完成多項任務。但我不熟悉BB10。你可以附加一個調試器並在呼叫站點捕獲異常嗎?從'io_service'構造函數拋出異常嗎?看到堆棧跟蹤會很有用。 –
到目前爲止,我還沒有成功進入Boost代碼本身,但它絕對是瞄準的方法 - 敬請期待。 –
它可能是'boost/asio/detail/impl/posix_mutex.ipp',這是我能夠找到'system_error'用字符串'「mutex」'拋出的唯一地方。假設BB10是posix,如果互斥量已經被初始化,'pthread_mutex_init'可能會失敗。堆棧跟蹤將在這裏幫助。 –