[英]How do I automatically destroy child processes in Windows?
在C ++ Windows應用程序中,我啟動了幾個長時間運行的子進程(當前我使用CreateProcess(...)來執行此操作。
如果主進程崩潰或關閉,我希望子進程自動關閉。
由於需要在“父”崩潰時起作用,因此我認為這需要使用操作系統的某些API /功能來完成。 這樣就清除了所有“子”過程。
我該怎么做呢?
Windows API支持稱為“作業對象”的對象。 以下代碼將創建一個“作業”,該作業被配置為在主應用程序結束時(清理其句柄時)關閉所有進程。 該代碼只能運行一次。
HANDLE ghJob = CreateJobObject( NULL, NULL); // GLOBAL
if( ghJob == NULL)
{
::MessageBox( 0, "Could not create job object", "TEST", MB_OK);
}
else
{
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
// Configure all child processes associated with the job to terminate when the
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if( 0 == SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
::MessageBox( 0, "Could not SetInformationJobObject", "TEST", MB_OK);
}
}
然后,在創建每個子進程時,執行以下代碼以啟動每個子進程並將其添加到作業對象:
STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;
// Launch child process - example is notepad.exe
if (::CreateProcess( NULL, "notepad.exe", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
::MessageBox( 0, "CreateProcess succeeded.", "TEST", MB_OK);
if(ghJob)
{
if(0 == AssignProcessToJobObject( ghJob, processInfo.hProcess))
{
::MessageBox( 0, "Could not AssignProcessToObject", "TEST", MB_OK);
}
}
// Can we free handles now? Not sure about this.
//CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
VISTA注意:如果您在Vista上遇到AssignProcessToObject()的訪問被拒絕的問題,請參閱Vista上的AssignProcessToJobObject始終返回“拒絕訪問” 。
一個有點棘手的解決方案是將父進程作為調試器附加到每個子進程(使用DebugActiveProcess )。 當調試器終止時,其所有調試進程也將終止。
更好的解決方案(假設您也編寫了子進程)是讓子進程監視父進程,並在父進程消失時退出。
Windows Job Objects聽起來是一個不錯的起點。 Job Object的名稱必須是眾所周知的,或傳遞給子代(或繼承該句柄)。 當家長死亡時,需要通過失敗的IPC“心跳”或僅在家長的進程句柄上的WFMO / WFSO來通知孩子。 屆時,任何子進程都可以使用TermianteJobObject降低整個組的工作效率。
您可以保持單獨的監視程序運行。 它的唯一任務是觀察當前的過程空間以發現您所描述的情況。 它甚至可以在崩潰后重新啟動原始應用程序,或向用戶提供不同的選項,收集調試信息等。只需嘗試使其足夠簡單即可,您就不需要第二個看門狗來監視第一個。
您可能必須保留啟動進程的列表,並在退出程序時將其一一殺死。 我不確定在C ++中執行此操作的具體細節,但這並不難。 困難的部分可能是確保在應用程序崩潰時關閉子進程。 .Net能夠添加一個功能,該功能在發生未處理的異常時被調用。 我不確定C ++是否提供相同的功能。
您可以將每個進程封裝在C ++對象中,並在全局范圍內保留它們的列表。 析構函數可以關閉每個進程。 如果程序正常退出但崩潰了,那么所有的賭注都關閉了,這樣就可以正常工作。
這是一個粗略的示例:
class myprocess
{
public:
myprocess(HANDLE hProcess)
: _hProcess(hProcess)
{ }
~myprocess()
{
TerminateProcess(_hProcess, 0);
}
private:
HANDLE _hProcess;
};
std::list<myprocess> allprocesses;
然后,每當啟動一個時,調用allprocessess.push_back(hProcess);。
就在我的頭頂上:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.