使用ExitProcess退出時為什么還會報運行時錯誤


通常情況下會以為ExitProcess就是直接結束並退出進程,其實不然,根據MSDN說明,調用ExitProcess至少在用戶態下有這些動作

1)除了調用ExitProcess的線程之外,其他線程均被結束,但線程使用的DLL不會接收到DLL_THREAD_DETACH事件(正常結束線程或釋放DLL則會有DLL_THREAD_DETACH事件)!

2)所有被結束的線程均設置為有信號,這樣意味着如果在某些地方調用WaitForSingleObject等待線程結束的,則會馬上獲得信號並結束等待

3)所有被加載的DLL,均會調用入庫函數並接收DLL_PROCESS_DETACH事件,這樣意味這在Delphi里,所有單元的finalization的代碼會被執行,同時也會清理運行時相關環境(大部分是system.pas,sysinit.pas里的)

4)結束當前線程和進程,這里會調用系統內部的功能代碼去釋放一些被系統認為是系統的資源(各種句柄和被系統管理的內存等)

5)進程的狀態從STILL_ACTIVE變為ExitCode,完成退出進程(但該進程其實在系統中仍然有相關的資源存在的,不然其他進程怎么獲取到這個ExitCode呢?只有再進程最后一個句柄關閉時,該進程的對象才會被釋放)

 

另外:

A. 如果在步驟1中被結束的線程中,如果在釋放相關的DLL時又調用ExitProcess,也就是除了當前調用ExitProcess的線程,有其他線程也調用了ExitProcess,則會導致死鎖。

B. 如果不是調用ExitProcess來結束進程,而是直接調用TerminateProcess,則相關的DLL不會被正常通知釋放,也就是DLL的入口函數不會被以DLL_PROCESS_DETACH事件調用,這樣也意味着Delphi里,所有單元的finalization的代碼不會被執行,運行時相關環境也不會被釋放!

在DLL中調用ExitProcess很容易導致一些錯誤,因為邏輯上講,調用ExitProcess的DLL本身也會被釋放調用,一旦該DLL的運行環境被釋放(相當於自己釋放自己),那正在執行的釋放過程會很容易出現內存溢出或導致系統資源未正常釋放而報錯。除非在調用ExitProcess前已經釋放了其他DLL和自身的資源,這時候才能最大限度保證不出錯,而一般較為復雜的源碼結構所編譯的DLL,想要正確釋放資源也不是一件容易的事。

 

下面看一下ExitProcess的偽代碼,幫助理解:

VOID
WINAPI
ExitProcess(
    UINT uExitCode
    )
{
    // 步驟 1和 步驟 2
    Status = NtTerminateProcess(NULL,(NTSTATUS)uExitCode);
    // 步驟 3
    LdrShutdownProcess(); 
    // 步驟 4,5....
    CsrClientCallServer();
    NtTerminateProcess(NtCurrentProcess(),(NTSTATUS)uExitCode);

}

 

此外可以調用ntdll的NtTerminateProcess函數結束進程,該函數直接進入內核態結束進程,會造成一些系統資源無法釋放,用戶態的資源更別想釋放了,所以,如果是實在不想看到錯誤提示框,就調用該函數吧,謹慎使用!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM