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

StackOverflow https://stackoverflow.com/questions/53208

  •  09-06-2019
  •  | 
  •  

Вопрос

В приложении 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);
    }
}

Затем, когда каждый дочерний процесс будет создан, выполните следующий код, чтобы запустить каждый дочерний процесс each и добавить его в объект job:

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.

Другие советы

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

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

Объекты заданий Windows - это хорошее место для начала.Имя объекта Job должно быть хорошо известно или передаваться дочерним элементам (или наследовать дескриптор).Дочерние элементы должны быть уведомлены, когда родитель умирает, либо из-за сбоя IPC "heartbeat", либо просто 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