代码之家  ›  专栏  ›  技术社区  ›  jm.

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

  •  61
  • jm.  · 技术社区  · 16 年前

    在C++ Windows应用程序中,我启动了几个长时间运行的子进程(当前我使用CealPoalPosits(…)来实现这一过程。

    我希望子进程自动关闭 如果我的主要进程崩溃 或者是关闭的。

    由于这需要对“父级”崩溃起作用,我认为这需要使用操作系统的一些API/特性来完成。以便清理所有“子”进程。

    我该怎么做?

    7 回复  |  直到 11 年前
        1
  •  67
  •   KindDragon    11 年前

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

    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 always return "access denied" on Vista 如果在vista上遇到assignprocesstoobject()的拒绝访问问题。

        2
  •  5
  •   Rob Walker    16 年前

    一个有点黑客的解决方案是父进程作为调试器附加到每个子进程(使用 DebugActiveProcess )当调试器终止时,它的所有调试对象进程也将终止。

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

        3
  •  3
  •   Adam Mitz    16 年前

    Windows作业对象听起来是个不错的开始。作业对象的名称必须是众所周知的,或者传递给子对象(或者继承句柄)。当父进程死亡时,需要注意子进程,无论是通过失败的ipc“heartbeat”还是仅通过父进程句柄上的wfmo/wfso。在这一点上,任何子进程都可以terminateJobobject来关闭整个组。

        4
  •  0
  •   silverArc    16 年前

    您可以保持单独的看门狗进程运行。它唯一的任务是观察当前的流程空间,以发现您所描述的情况。它甚至可以在崩溃后重新启动原始应用程序,或者为用户提供不同的选项、收集调试信息等。只需尽量保持足够简单,这样就不需要第二个监视器来监视第一个监视器。

        5
  •  -2
  •   Kibbee    16 年前

    您可能需要保留一个您启动的进程的列表,并在退出程序时一个接一个地删除它们。我不确定在C++中做这件事的细节,但不难。困难的部分可能是确保在应用程序崩溃的情况下关闭子进程。.NET能够添加在发生未处理的异常时调用的get函数。我不确定C++是否提供了相同的功能。

        6
  •  -2
  •   Adam Pierce    16 年前

    可以将每个进程封装在C++对象中,并将它们保存在全局范围内。析构函数可以关闭每个进程。如果程序正常退出,但它崩溃了,所有的赌注都取消了,那就没问题了。

    下面是一个粗略的例子:

    class myprocess
    {
    public:
        myprocess(HANDLE hProcess)
            : _hProcess(hProcess)
        { }
    
        ~myprocess()
        {
            TerminateProcess(_hProcess, 0);
        }
    
    private:
        HANDLE _hProcess;
    };
    
    std::list<myprocess> allprocesses;
    

    然后,无论何时启动一个,都要调用allprocessess.push-back(hprocess);

        7
  •  -4
  •   Dominik Grabiec    16 年前

    就在我头顶上:

    • 您是否考虑过使用线程而不是进程?
    • 尝试将主线程/进程的句柄传递给子进程,让它们等待该句柄。这适用于线程,因为在线程句柄上等待直到该线程完成并退出。不太确定它是否适用于进程,应该检查msdn以验证这一点。