發布時間:2011-08-29 共3頁
在Windows操作系統中,DLL(動態鏈接庫)技術有很多優點。例如,多個應用程序可以共享一個DLL文件,真正實現了資源"共享",大大縮小了應用程序的執行代碼,有效地利用了內存,而且DLL文件作為一個單獨的程序模塊,封裝性、獨立性好,有利于提高軟件開發和維護的效率。
DllMain是可選擇的DLL入口指針,當進程和線程啟動和終止時被系統調用,分別進行創建資源和釋放資源等操作,特別地,也可以在DLL被裝載進進程空間時(即DllMain響應DLL_PROCESS_ATTACH通知時)創建線程,在DLL從進程空間卸載時(即DllMain響應 DLL_PROCESS_DETACH通知時)結束線程。但是,在DllMain中無論是創建線程還是結束線程,都特別要注意一個規則,那就是 DllMain的順序調用規則。
1、DllMain的順序調用規則
Windows操作系統中是順序調用DLL的入口函數DllMain的。當進程被創建時,系統也為該進程創建了一個互斥對象。每個進程都有它自己的互斥對象。進程互斥對象的一個作用是,序列化在需要調用DllMain的 4種情況下DllMain的執行:DLL_PROCESS_ATTACH、DLL_THREAD_ATTACH、DLL_THREAD_DETACH和 DLL_PROCESS_DETACHDLL。DllMain函數的第二個參數指示出調用DllMain的原因。
在DllMain中創建線程或終止線程時,如果違背了DllMain的這個順序調用規則,程序就會發生死鎖。下面就DllMain中創建線程和終止線程兩種情況下的死鎖分別進行講述。
2、DllMain中創建和終止線程時的死鎖
2.1、裝載DLL時創建的線程的為什么沒有運行
考慮在一個多線程程序中,某個DLL被加載進程地址空間時,該DLL的DllMain啟動了一個線程,然后立即調用一個應答事件對象的 WaitForSingleObject函數,以確認在繼續進行其余的DllMain處理之前,新產生的線程能夠正確地執行一些操作。類似的代碼如下:
//----------------------start ------------
HANDLE g_thread_handle =NULL; // 該DLL內部線程的句柄
DWORD g_thread_id =0; // 該DLL內部線程的ID
HANDLE g_hEvent=NULL;// 應答事件的句柄
DWORD WINAPI InSideDll_ThreadProc( LPVOID p )
{
/* 表示一些操作。
如果“---- operations.----”被打印到Output窗口中了,
說明本線程函數在被執行了。 */
OutputDebugString(“---- operations.---- \n”);
/* InSideDll_ThreadProc的操作完成后,
通知在g_hEvent處等待的線程,可以繼續運行了。*/
SetEvent(g_hEvent);
return 1;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//DLL正在映射到進程地址空間中
{
// 禁止線程庫調用,
DisableThreadLibraryCalls((HINSTANCE)hModule);
// 創建DLL內線程使用的事件對象
g_hEvent = ::CreateEvent( NULL, FALSE, FALSE, _T("hello11" ));
//創建DLL內線程對象
g_thread_handle = ::CreateThread(NULL,0,
InSideDll_ThreadProc,(LPVOID)0,0, &( g_thread_id) ) ;
// 等待剛創建的線程完成相關操作
::WaitForSingleObject( g_hEvent, INFINITE );