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

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

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

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

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

Ответ 1

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.

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

Вам, вероятно, придется вести список процессов, которые вы запускаете, и убивать их один за другим, когда вы выходите из своей программы. Я не уверен в специфике этого в С++, но это не должно быть сложно. Трудная часть, вероятно, будет гарантировать, что дочерние процессы будут завершены в случае сбоя приложения..Net имеет возможность добавлять функцию, вызываемую при возникновении необработанного исключения. Я не уверен, что С++ предлагает те же возможности.

Ответ 6

Вы можете инкапсулировать каждый процесс в объект С++ и сохранить его список в глобальной области. Деструкторы могут отключать каждый процесс. Это будет нормально работать, если программа выйдет нормально, но она сработает, все ставки отключены.

Вот пример:

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

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

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

Затем, когда вы запустите его, вызовите allprocessess.push_back (hProcess);

Ответ 7

Сверху моей головы:

  • Рассматривали ли вы использование потоков вместо процессов?
  • Попробуйте передать дескриптор основного потока/процесса дочерним процессам и заставить их ждать этого дескриптора. Это работает для потоков, так как ожидание на ручке потока ожидает, пока этот поток не завершится и не завершится. Не уверен, будет ли он работать для процессов, проверьте MSDN, чтобы проверить это.