2009-07-16 3 views
4

Вопрос: Как я могу определить все процессы в дереве процессов , чтобы убить их?Как завершить все дочерние процессы [grand] с использованием C# на WXP (и более поздних MSWindows)

У меня есть приложение, написанная на C#, который будет:

  1. Получить набор данных от сервера,
  2. икры третьей утилиты стороны обрабатывать данные, а затем
  3. Верните результаты на сервер.

Это прекрасно работает. Но так как пробег расходует много из CPU и может занять до тех пор, как час, я хочу добавить, чтобы мое приложение завершило его дочерние процессы.

Некоторые вопросы, которые делают простые решения, я нашел в других местах:

  • моего приложения в дочерний процесс «A» (InstallAnywhere EXE я думаю) порождает реальную обработку приложение «B» (в Java. exe), который в свою очередь порождает больше детей «C1» .. «Cn» (большинство из них также написаны на Java).
  • Скорее всего будет несколько экземпляров моего приложения (и, следовательно, нескольких наборов его дочерних элементов), работающих на одном компьютере.
  • Детский процесс не контролируется, поэтому в будущем могут возникнуть некоторые процессы «D».
  • Мое приложение должно работать на 32-битных и 64-разрядных версиях MSWindows.

На стороне плюса нет проблемы потери данных, «чистое» выключение не имеет значения, пока процессы заканчиваются довольно быстро.

ответ

2

Я думаю, вы можете убить своих внуков этим кодом от the MSDN forums.

public bool killProcess(int pid) 
{ 
    bool didIkillAnybody = false; 
    try 
    { 
    Process[] procs = Process.GetProcesses(); 
    for (int i = 0; i < procs.Length; i++) 
    { 
    didIkillAnybody = GetParentProcess(procsIdea.Id) == pid) && 
            killProcess(procsIdea.Id); 
    } 
    try 
    { 
    Process myProc = Process.GetProcessById(pid); 
    myProc.Kill(); 
    return true; 
    } 
    catch { } 
    } 
    catch (Exception ex) 
    { 
    try 
    { 
    new Logger().Write("Exception caught at JobExecution.killProcess()", ex.Message, System.Diagnostics.EventLogEntryType.Warning, false); 
    } 
    catch { } 
    } 
    return didIkillAnybody; 
} 

private int GetParentProcess(int Id) 
{ 
    int parentPid = 0; 
    using (ManagementObject mo = new ManagementObject("win32_process.handle='" + Id.ToString() + "'")) 
    { 
    mo.Get(); 
    parentPid = Convert.ToInt32(mo["ParentProcessId"]); 
    } 
    return parentPid; 
} 
+1

В моем случае «B» может породить еще один «C», если я не убивал «B» первым , так что это не сработает, но это привело меня к правильному ответу. Мне нужно было получить список идентификаторов процессов и * затем * убить их сверху вниз. Мое решение строит дерево за один проход через Process.GetProcesses(), тогда вызывающий может убить их сверху вниз или снизу вверх или может просто использовать данные дерева. – NVRAM

1

Я протестировал решение Джейка Пирсона, и для меня это не всегда работает. Я хотел убить другой процесс (с известным pid) деревом. В другом процессе использовался iexplore.exe, выполняемый отдельно для каждого экземпляра (IE 8 - более одного процесса). Он отлично работает, но при использовании с WinAPI для скрытия окна IE он перестает работать.

Я нашел solution on microsoft.public.dotnet.framework group, и теперь он отлично работает. Я думаю, что ответ Джейка может быть полезен в большинстве случаев.

+0

Это собирает всех детей в ArrayList, а не как дерево (и это излишне рекурсивно). Рад, что вы нашли свое решение, но я ненавижу PInvokes и избегаю их, как чуму. – NVRAM

+0

Мне тоже не нравится PInvokes, но, к сожалению, мне нужно что-то делать, что требует от меня многого:/Надеюсь, это решение будет полезно для кого-то другого, ищущего его :) – prostynick

2

Следующий код работает для меня:

private void KillProcessAndChildren(int pid) 
{ 
    using (var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid)) 
    using (ManagementObjectCollection moc = searcher.Get()) 
    { 
    foreach (ManagementObject mo in moc) 
    { 
     KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"])); 
    } 
    try 
    { 
     Process proc = Process.GetProcessById(pid); 
     proc.Kill(); 
    } 
    catch (ArgumentException) 
    { /* process already exited */ } 
    } 
} 

Он работает для сценария у меня есть. Мне было бы интересно услышать, что это работает и для других.

+0

Хорошо работает для меня. Однако обратите внимание, что и «ManagementObjectSearcher», и «ManagementObjectCollection» являются одноразовыми и поэтому должны быть помещены в блоки «использования». – ladenedge

+0

+1. Работает на меня. Я редактировал используемые блоки в вашем ответе для будущих пользователей. –

2

На основе решения изложенных на этом сайте, здесь это компактный способ сделать это:

static public void KillChildren(int parentPid) 
    { 
     foreach (var pid in 
      from ManagementBaseObject m in new ManagementObjectSearcher("select ProcessId from Win32_Process where ParentProcessId=" + parentPid).Get() 
      select Convert.ToInt32(m["ProcessId"])) 
      KillChildren(pid); 
     Process.GetProcessById(parentPid).Kill(); 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^