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

发布于 2024-07-06 03:08:36 字数 203 浏览 16 评论 0 原文

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

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

需要解决“父”崩溃的问题,我相信这需要使用操作系统的某些 API/功能来完成,以便清理所有“子”进程

由于 我这样做吗?

In C++ Windows app, I launch several long running child processes (currently I use CreateProcess(...) to do this.

I want the child processes to be automatically closed if my main processes crashes or is closed.

Because of the requirement that this needs to work for a crash of the "parent", I believe this would need to be done using some API/feature of the operating system. So that all the "child" processes are cleaned up.

How do I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

剑心龙吟 2024-07-13 03:08:37

您可以在创建进程之前将作业分配给父进程:

static HANDLE hjob_kill_on_job_close=INVALID_HANDLE_VALUE;
void init(){
    hjob_kill_on_job_close = CreateJobObject(NULL, NULL);
    if (hjob_kill_on_job_close){
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobli = { 0 };
        jobli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        SetInformationJobObject(hjob_kill_on_job_close,
            JobObjectExtendedLimitInformation,
            &jobli, sizeof(jobli));
        AssignProcessToJobObject(hjob_kill_on_job_close, GetCurrentProcess());
    }
}
void deinit(){
    if (hjob_kill_on_job_close) {
        CloseHandle(hjob_kill_on_job_close);
    }
}

当作业的最后一个句柄关闭时,JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 会导致与该作业关联的所有进程终止。 默认情况下,所有子进程都会自动分配给作业,除非您在调用 CreateProcess 时传递了 CREATE_BREAKAWAY_FROM_JOB。 请参阅 https://learn.microsoft.com/en -us/windows/win32/procthread/process-creation-flags 了解有关 CREATE_BREAKAWAY_FROM_JOB 的更多信息。

您可以使用 Sysinternals 中的流程资源管理器来确保所有流程都分配给该作业。 像这样:
输入图片此处描述

You can assign a job to the parent process before creating processes:

static HANDLE hjob_kill_on_job_close=INVALID_HANDLE_VALUE;
void init(){
    hjob_kill_on_job_close = CreateJobObject(NULL, NULL);
    if (hjob_kill_on_job_close){
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobli = { 0 };
        jobli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
        SetInformationJobObject(hjob_kill_on_job_close,
            JobObjectExtendedLimitInformation,
            &jobli, sizeof(jobli));
        AssignProcessToJobObject(hjob_kill_on_job_close, GetCurrentProcess());
    }
}
void deinit(){
    if (hjob_kill_on_job_close) {
        CloseHandle(hjob_kill_on_job_close);
    }
}

JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE causes all processes associated with the job to terminate when the last handle to the job is closed. By default, all child processes will be assigned to the job automatically, unless you passed CREATE_BREAKAWAY_FROM_JOB when calling CreateProcess. See https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags for more information about CREATE_BREAKAWAY_FROM_JOB.

You can use process explorer from Sysinternals to make sure all processes are assigned to the job. Just like this:
enter image description here

飘落散花 2024-07-13 03:08:37

Windows 作业对象听起来是一个不错的起点。 作业对象的名称必须是众所周知的,或者传递给子对象(或继承句柄)。 当父进程死亡时,子进程需要得到通知,无论是通过失败的 IPC“心跳”还是仅通过父进程句柄上的 WFMO/WFSO。 此时,任何子进程都可以通过 TermianteJobObject 来破坏整个组。

Windows Job Objects sounds like a good place to start. The name of the Job Object would have to be well-known, or passed to the children (or inherit the handle). The children would need to be notice when the parent dies, either through a failed IPC "heartbeat" or just WFMO/WFSO on the parent's process handle. At that point any child process could TermianteJobObject to bring down the whole group.

独留℉清风醉 2024-07-13 03:08:37

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

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

One somewhat hackish solution would be for the parent process to attach to each child as a debugger (use DebugActiveProcess). When a debugger terminates all its debuggee processes are terminated as well.

A better solution (assuming you wrote the child processes as well) would be to have the child processes monitor the parent and exit if it goes away.

蓝咒 2024-07-13 03:08:37

您可以将每个进程封装在一个 C++ 对象中,并在全局范围内保留它们的列表。 析构函数可以关闭每个进程。 如果程序正常退出,那会工作得很好,但如果它崩溃了,所有的赌注都会被取消。

这是一个粗略的例子:

class myprocess
{
public:
    myprocess(HANDLE hProcess)
        : _hProcess(hProcess)
    { }

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

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

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

You could encapsulate each process in a C++ object and keep a list of them in global scope. The destructors can shut down each process. That will work fine if the program exits normally but it it crashes, all bets are off.

Here is a rough example:

class myprocess
{
public:
    myprocess(HANDLE hProcess)
        : _hProcess(hProcess)
    { }

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

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

Then whenever you launch one, call allprocessess.push_back(hProcess);

苍白女子 2024-07-13 03:08:37

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

You'd probably have to keep a list of the processes you start, and kill them off one by one when you exit your program. I'm not sure of the specifics of doing this in C++ but it shouldn't be hard. The difficult part would probably be ensuring that child processes are shutdown in the case of an application crash. .Net has the ability to add a function that get's called when an unhandled exception occurs. I'm not sure if C++ offers the same capabilities.

原谅我要高飞 2024-07-13 03:08:37

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

You can keep a separate watchdog process running. Its only task is watching the current process space to spot situations like you describe. It could even re-launch the original application after a crash or provide different options to the user, collect debug information, etc. Just try to keep it simple enough so that you don't need a second watchdog to watch the first one.

如何视而不见 2024-07-13 03:08:36

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 上始终返回“访问被拒绝”拒绝在 Vista 上使用 AssignProcessToObject() 的问题。

The Windows API supports objects called "Job Objects". The following code will create a "job" that is configured to shut down all processes when the main application ends (when its handles are cleaned up). This code should only be run once.:

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);
    }
}

Then when each child process is created, execute the following code to launch each child each process and add it to the job object:

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 NOTE: See AssignProcessToJobObject always return "access denied" on Vista if you encounter access-denied issues with AssignProcessToObject() on vista.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文