如何在Windows中自动销毁子进程?
在C ++ Windows应用程序中,我启动了几个长时间运行的子进程(当前我使用CreateProcess(...)来执行此操作。
如果主进程崩溃或者关闭,我希望子进程自动关闭。
由于要求这需要在"父"崩溃时起作用,因此我认为需要使用操作系统的某些API /功能来完成。这样就清除了所有"子"过程。
我该怎么做呢?
解决方案
回答
我们可能必须保留启动进程的列表,并在退出程序时将它们一一杀死。我不确定在C ++中执行此操作的具体细节,但这并不难。困难的部分可能是确保在应用程序崩溃的情况下关闭子进程。 .Net可以添加在发生未处理的异常时调用的函数。我不确定C ++是否提供相同的功能。
回答
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)。当调试器终止时,其所有被调试进程也将终止。
更好的解决方案(假设我们也编写了子进程)是让子进程监视父进程,并在父进程消失时退出。
回答
我们可以将每个进程封装在一个C ++对象中,并在全局范围内保留它们的列表。析构函数可以关闭每个进程。如果程序正常退出但崩溃了,那么所有的赌注都关闭了,这样就可以正常工作。
这是一个粗略的示例:
class myprocess { public: myprocess(HANDLE hProcess) : _hProcess(hProcess) { } ~myprocess() { TerminateProcess(_hProcess, 0); } private: HANDLE _hProcess; }; std::list<myprocess> allprocesses;
然后,每当启动一个时,调用allprocessess.push_back(hProcess);。
回答
就在我的头顶上:
- 我们是否考虑过使用线程而不是进程?
- 尝试将主线程/进程的句柄传递给子进程,让它们在该句柄上等待。这适用于线程,因为等待线程句柄一直等待到该线程完成并退出。不太确定它是否适用于流程,应签出MSDN进行验证。
回答
Windows Job Objects听起来是一个不错的起点。作业对象的名称必须是众所周知的,或者传递给子代(或者继承该句柄)。当父母死亡时,需要通过失败的IPC"心跳"或者父母的进程句柄上的WFMO / WFSO来通知孩子。届时,任何子进程都可以使用TermianteJobObject降低整个组的工作效率。