关于进程:如何在Windows中自动销毁子进程?

关于进程:如何在Windows中自动销毁子进程?

How do I automatically destroy child processes in Windows?

在C ++ Windows应用程序中,我启动了几个长时间运行的子进程(当前我使用CreateProcess(...)来执行此操作。

如果主进程崩溃或关闭,我希望子进程自动关闭。

由于需要在"父"崩溃时起作用,因此我认为这需要使用操作系统的某些API /功能来完成。 这样就清除了所有"子"过程。

我该怎么做呢?


Windows API支持称为"作业对象"的对象。以下代码将创建一个"作业",该作业被配置为在主应用程序结束时(清理其句柄时)关闭所有进程。该代码只能运行一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
    }
}

然后,在创建每个子进程时,执行以下代码以启动每个子进程并将其添加到作业对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 ++对象中,并在全局范围内保留它们的列表。析构函数可以关闭每个进程。如果程序正常退出但崩溃了,那么所有的赌注都关闭了,这样就可以正常工作。

这是一个粗略的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class myprocess
{
public:
    myprocess(HANDLE hProcess)
        : _hProcess(hProcess)
    { }

    ~myprocess()
    {
        TerminateProcess(_hProcess, 0);
    }

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

然后,每当启动一个时,调用allprocessess.push_back(hProcess);。


您可能必须保留启动进程的列表,并在退出程序时将其一一杀死。我不确定在C ++中执行此操作的具体细节,但这并不难。困难的部分可能是确保在应用程序崩溃时关闭子进程。 .Net能够添加一个功能,该功能在发生未处理的异常时被调用。我不确定C ++是否提供相同的功能。


就在我的头顶上:

  • 您是否考虑过使用线程而不是进程?
  • 尝试将主线程/?痰木浔莞咏蹋⑹顾窃诟镁浔系却U馐视糜谙叱蹋蛭却叱叹浔恢钡鹊礁孟叱掏瓿刹⑼顺觥2惶范ㄋ欠袷视糜诮蹋η┏鯩SDN进行验证。

推荐阅读