精品理论电影在线_日韩视频一区二区_一本色道精品久久一区二区三区_香蕉综合视频

DllMain和多線程死鎖

發布時間:2011-08-29 共3頁

  // 清除資源

  ::CloseHandle(g_thread_handle);

  g_thread_id = 0 ;

  g_thread_handle = NULL ;

  ::CloseHandle(g_hEvent);

  g_hEvent=NULL;

  }

  break;

  case DLL_PROCESS_DETACH:

  // DLL正在從進程地址空間中卸載

  break;

  }

  return TRUE;

  }

  //----------------------end   ------------

  如果對這樣的程序進行調試,通過Call Stack窗口可以看到該程序正在等待DllMain內部的線程處理,而Output窗口中也沒有打印出“---- operations.---- ”語句。可見線程函數InSideDll_ThreadProc根本就沒有得到運行的機會。

  結合DllMain的順序調用規則,答案就很簡單了。在程序運行過程中,第一個線程對LoadLibrary的調用引起操作系統獲取進程互斥對象并以DLL_PROCESS_ATTACH值調用該DLL的DllMain。該DLL的DllMain函數產生第二個線程。無論何時當進程產生一個新線程時,操作系統將獲取進程互斥對象,以便于它可以為DLL_THREAD_ATTACH值調用每個加載的DLL的DllMain函數。在這個特定的程序中,第二個線程阻塞,因為第一個線程還保持著進程互斥對象。不幸的是,第一個線程然后調用WaitForSingleObject確認第二個線程能夠正確地完成一些操作。因為第二個線程被阻塞在進程互斥對象上,這個進程互斥對象還被第一個線程所持有,而第一個線程要等待第二個線程從而也被阻塞,結果就導致了死鎖。如下圖所示。

  另外,DisableThreadLibraryCalls函數并不能解除這種死鎖,相關原因在《Windows核心編程》一書中有更詳盡的描述,這里就不再贅述了。

  2.2、卸載DLL時內部線程為什么沒有完全退出

  估計很多人都知道裝載DLL過程中的多線程死鎖是因為DllMain的順序調用規則,但是很少人了解卸載DLL過程中的多線程死鎖也是由于同樣的原因。例如,如果一個DLL的DllMain的代碼寫成下面的形式,且進程中有至少一個DLL的DllMain沒有調用DisableThreadLibraryCalls函數的話,那么卸載該DLL過程中就會因為 DllMain的順序操作特性帶來DLL內部線程沒有完全退出的錯誤。

  //----------------------start   ------------

  HANDLE       g_thread_handle =NULL;       // 該DLL內部線程的句柄

  DWORD       g_thread_id =0;       // 該DLL內部線程的ID

  HANDLE g_hEvent=NULL;// 應答事件的句柄

  DWORD WINAPI InSideDll_ThreadProc( LPVOID p )

  {

  while(1){

  // 收到通知就退出線程函數

  DWORD ret = ::WaitForSingleObject( g_hEvent, INFINITE );

  if(WAIT_TIMEOUT = =ret|| WAIT_OBJECT_0 = =ret) break;

  }

  return true ;

  }

  BOOL APIENTRY DllMain( HANDLE hModule,

  DWORD   ul_reason_for_call,

  LPVOID lpReserved

  )

  {

  switch (ul_reason_for_call)

  {

  case DLL_PROCESS_ATTACH:

  //線程正在映射到進程地址空間中

  {

  // 創建DLL內的線程使用的事件對象

  g_hEvent = ::CreateEvent( NULL, FALSE, FALSE, _T("hello11" ));

百分百考試網 考試寶典

立即免費試用