各位大俠:
本人用Delphi2010開發的程式,其中使用了TMS6.9組件包中的TAdvTrackBar控制元件,在Win7,Win8都運行正常,但在Win XP上就會導致行程無法結束,從而導致后續無法啟動該程式,請問是什么情況?有沒有人碰到過啊?
謝謝了!
uj5u.com熱心網友回復:
感覺好想是在DLL中使用TAdvTrackBar的原因,因為在EXE中使用正常。請大俠解答。uj5u.com熱心網友回復:
甚至不需要使用TAdvTrackBar這個控制元件,只需要加上 'Uses AdvTrackBar'這個陳述句就會導致這個問題!求解答,感覺是DLL釋放資源的問題。uj5u.com熱心網友回復:
反難說,問題所在。只能看原碼,才能分析。uj5u.com熱心網友回復:
網上發現如下解答,但是我該怎么修改呢?TMS組件是沒有原始碼的!
-------------------------------------------------------------------------------------------------------------
如果你在windows平臺開發元件,并且在鏈接庫啟動了內部執行緒,那么你很有可能發現加載你的DLL的程式在退出時會死鎖,有時候雖然主程式界面沒有了,但是打開任務管理器,發現行程還在。
最近做播放器插件開發,基于directshow、vlc、mplayer框架,各做了一個插件,三個插件中都使用了另外一個媒體DLL庫(Mylib.dll),并且都是通過動態加載(LoadLibrary)使用的。該DLL比較復雜,內部使用的執行緒;另外directshow、vlc的插件自身也是一個DLL,mplayer不支持動態插件,是內置原始碼編譯。
在沒有針對行程退出做處理時,三個播放器(基于directshow的播放器測驗了GraphEidt、Windows Media Player)都不能正常退出。
通過查看執行緒呼叫堆疊,是在Mylib.dll最后卸載時,dll的一個全域物件析構中,等待一個事件(Event)物件不回傳,而這個事件應該是另一個執行緒退出前設定為有信號,但是整個行程除了主執行緒外,其他執行緒都已經結束了,這說明執行緒是被強行結束了,主執行緒呼叫堆疊顯示已經進入了_ExitProcess中,應該是在此之前主執行緒殺死了所有子執行緒。
三個播放器框架都沒有找到退出通知的機制,所以能夠想到的辦法只有使用atexit,在程式結束時呼叫一個Mylib.dll停止介面(Mylib_Stop)。都是沒有效果,仍然不能正常退出。
但是與上面的情形不一樣的是,mplayer還是掛死在Mylib.dll中的全域物件析構中;directshow與vlc卻直接掛死在Mylib_Stop函式中,呼叫堆疊顯示正在等待另一個執行緒退出,但是這個執行緒卻在_ExitThread的地方卡住了。
要解決全域物件析構中的死鎖問題,需要讓執行緒正常退出,而不是被強行終止,因此需要在_ExitProcess前面卸載Mylib.dll。我們把這個任務增加到atexit的程序中,因為atexit的函式在退出主函式main后就會被呼叫,修改之后,mplayer真的可以正常退出了。
對于directshow與vlc,都是在一個插件DLL中啟動Mylib.dll,我們發現atexit注冊的函式,是在插件Dll卸載的時候被呼叫,呼叫堆疊中有DllMain函式。聯想到執行DllMain函式的一些細節,覺得情況應該是這樣:系統在呼叫DllMain時會有一個全域鎖,主執行緒已經進入DllMain,所有鎖已經被加上,另一個執行緒退出時也會呼叫DllMain,也需要這個鎖,這樣就造成了主執行緒等待另一個執行緒退出,而這個執行緒又在等待主執行緒占有的鎖,形成了死鎖情形。
另外在DLL中使用atexit注冊的函式,不像我們期望的那樣在行程退出時呼叫,而且在相應的DLL卸載時呼叫,這一點MSDN沒有說明,但是通過跟蹤到atexit里面,發現確實是根據DLL還是EXE分別處理的,同時也發現EXE中使用的是_imp___onexit函式。
嘗試用_imp___onexit替換atexit,編譯沒有問題,但是運行會crash,因為注冊的退出執行函式的代碼實際是在插件DLL,而這個DLL在行程退出前已經卸載,代碼頁面失效。
最終我們只能修改Mylib.dll,去除全域變數析構中的等待事件死鎖,并且不使用atexit,這樣能夠適應三個播放器;代價是Mylib.dll沒有正常終止,里面的執行緒被強行終止,有可能會有一些善后作業無法完成。
總結如下:1、帶有內部執行緒DLL要想正常退出,需要匯出一個退出函式介面,并且要求呼叫者在適當的時候呼叫。
2、要注意DLL中全域變數析構前,執行緒可能已經被強行終止,如果在析構中依賴某個執行緒完成一些作業,則要考慮這種可能性,但是直接等待執行緒句柄沒有問題
3、在DLL代碼中使用atexit注冊的函式,不能期望在行程退出時被呼叫,另外不管是在DLL還是EXE代碼中,不能將其他模塊的函式注冊到atexit中。
uj5u.com熱心網友回復:
感覺可能是GDI+的問題,GDI+有一個ShutDown退出的函式,這個單元一般要在宿主程式中參考,在DLL中參考,最后退出的時候會因為這個ShutDown關倍訓收GDI+資源而導致行程卡死。有一個方法,就是打包,吧TMS中GDI+的單元都打到包里面去,然后再宿主也就是exe主工程的工程檔案頭部先參考有這個ShutDown回收GDI+資源函式的單元,然后宿主工程和DLL工程都帶上這個帶有GDI+的包應該就可以了。轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/84816.html
標籤:VCL組件開發及應用
上一篇:這個控制元件的思路是什么?
下一篇:cxGrid的列如何支持多選框?
