Ⅰ 如何讓 windows 平台多線程 DLL 完整退出
如果你在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中。
Ⅱ MTK中怎樣創建和使用lib
� 2. make文件中COMPLIST加入mylib 3. 在REL_MMI_GPRS.mak中CUS_REL_MTK_COMP加入mylib 4. 在mtklib文件夾裡面放mylib,就ok啦。 方法一:MTK生成庫(ARM) 過程 第一步,生成真機的obj文件 第二步,找到相關的obj文件 D:\LongCheer\build\LC6225_GEMINI\gprs\MT6225o\mmi_app 第三步,把相關的obj文件拷貝到一個目錄下面 D:\lib_temp 第四步,打開命令窗口,輸入命令 armar -r temp.lib *.obj 生成 temp.lib 庫 第五步,輸入命令armar -tv temp.lib 可以看到加入的庫 也可以這樣armar -r xxx.lib x1.obj x2.obj。 方法二:在option.mak 中單獨添加一個模塊 COMPLIST += tmptmp 在make中添加tmptmp目錄及其那是個文件。