在 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 上,AssignProcessToJobObject 始终返回“访问被拒绝” 如果您在 Vista 上遇到分配进程到对象()拒绝访问的问题。

其他提示

一种有点黑客的解决方案是让父进程作为调试器附加到每个子进程(使用 调试活动进程)。当调试器终止时,其所有被调试进程也会终止。

更好的解决方案(假设您也编写了子进程)是让子进程监视父进程,并在父进程消失时退出。

Windows 作业对象听起来是一个不错的起点。作业对象的名称必须是众所周知的,或者传递给子对象(或继承句柄)。当父进程死亡时,子进程需要得到通知,无论是通过失败的 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);

就在我的头顶上:

  • 您是否考虑过使用线程而不是进程?
  • 尝试将主线程/​​进程的句柄传递给子进程并让它们等待该句柄。这适用于线程,因为等待线程句柄会等待该线程完成并退出。不太确定它是否适用于进程,应该查看 MSDN 来验证这一点。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top