Как автоматически уничтожить дочерние процессы в Windows?


в приложении C++ Windows я запускаю несколько длительных дочерних процессов (в настоящее время я использую CreateProcess(...) чтобы сделать это.

Я хочу, чтобы дочерние процессы будут автоматически закрыты Если мои основные процессы выходят из строя или закрыт.

из-за требования, что это должно работать для сбоя "родителя", я считаю, что это должно быть сделано с помощью некоторого API/функции операционной системы. Так что все" дочерние " процессы будут очищены вверх.

Как мне это сделать?

7 58

7 ответов:

API Windows поддерживает объекты, называемые "объектами заданий". В следующем коде будет создано "задание", настроенное на завершение всех процессов после завершения работы основного приложения (когда его дескрипторы будут очищены). Этот код должен выполняться только один раз.:

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 если вы столкнулись с проблемами доступа-отказано с AssignProcessToObject () на vista.

одно несколько хакерское решение было бы для родительского процесса, чтобы прикрепить к каждому ребенку в качестве отладчика (use DebugActiveProcess). Когда отладчик завершает работу, все его отладочные процессы также завершаются.

лучшим решением (предполагая, что вы также написали дочерние процессы) было бы, чтобы дочерние процессы контролировали родителя и выходили, если он уходит.

объекты задания Windows звучит как хорошее место для начала. Имя объекта задания должно быть хорошо известно или передаваться дочерним элементам (или наследовать дескриптор). Дети должны были бы быть замечены, когда родитель умирает, либо через неудачный IPC "heartbeat", либо просто WFMO/WFSO на дескрипторе процесса родителя. В этот момент любой дочерний процесс может TermianteJobObject сбить всю группу.

вы можете сохранить отдельный сторожевой процесс работает. Его единственная задача-наблюдать за текущим пространством процесса, чтобы определить ситуации, подобные описанным вами. Он может даже повторно запустить исходное приложение после сбоя или предоставить различные параметры пользователю, собирать отладочную информацию и т. д. Просто постарайтесь сделать это достаточно просто, чтобы вам не нужен второй сторожевой пес, чтобы наблюдать за первым.

вам, вероятно, придется сохранить список процессов, которые вы запускаете, и убить их один за другим при выходе из программы. Я не уверен в специфике выполнения этого в C++, но это не должно быть сложно. Трудная часть, вероятно, будет гарантировать, что дочерние процессы завершаются в случае сбоя приложения. .Net имеет возможность добавлять функцию, которая вызывается get при возникновении необработанного исключения. Я не уверен, что 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, чтобы проверить это.