Process.Kill()似乎没有杀死进程

时间:2015-05-15 00:57:12

标签: c# .net process kill

我在使用Process.Kill()时遇到问题。我想我一定是在误解它是如何运作的。这是我的测试功能。我启动了一个长时间运行的进程(ping -t),然后在五秒钟后终止它。

我可以看到ping进程显示,但程序结束后进程仍然存在。我必须手动杀死它。

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe");
Process process = new Process();

startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = "/c ping -t 8.8.8.8";

Console.WriteLine("Staring ping process");
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);
Thread.Sleep(5000);

Console.WriteLine("Killing ping process");
process.Kill();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

我在这里做错了什么?

5 个答案:

答案 0 :(得分:17)

您启动了cmd.exe,然后cmd.exe启动子进程ping.exe。要杀死ping.exe,您可以终止所有进程层次结构。例如,使用WMI(添加System.Management引用):

private static void KillProcessAndChildrens(int pid)
{
    ManagementObjectSearcher processSearcher = new ManagementObjectSearcher
      ("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection processCollection = processSearcher.Get();

    try
    {
        Process proc = Process.GetProcessById(pid);
        if (!proc.HasExited) proc.Kill();
    }
    catch (ArgumentException)
    {
        // Process already exited.
    }

    if (processCollection != null)
    {
        foreach (ManagementObject mo in processCollection)
        {
            KillProcessAndChildrens(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.)
        }
    }
}

答案 1 :(得分:5)

这是@SulNR答案的补丁,因为它的答案会泄漏子进程的子进程。

private static void KillProcessAndChildrens(int pid)
{
    ManagementObjectSearcher processSearcher = new ManagementObjectSearcher
      ("Select * From Win32_Process Where ParentProcessID=" + pid);
    ManagementObjectCollection processCollection = processSearcher.Get();

    // We must kill child processes first!
    if (processCollection != null)
    {
        foreach (ManagementObject mo in processCollection)
        {
            KillProcessAndChildrens(Convert.ToInt32(mo["ProcessID"])); //kill child processes(also kills childrens of childrens etc.)
        }
    }

    // Then kill parents.
    try
    {
        Process proc = Process.GetProcessById(pid);
        if (!proc.HasExited) proc.Kill();
    }
    catch (ArgumentException)
    {
        // Process already exited.
    }
}

答案 2 :(得分:1)

FWIW 一个 VS2019 Visual Basic 版本 Julio 的修改。

   Private Sub KillProcessAndChildrens(pintPID As Integer)

      Dim processSearcher As New ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pintPID.ToString)

      Dim processCollection As ManagementObjectCollection = processSearcher.Get()
      '     We must kill child processes first!
      If Not IsNothing(processCollection) Then
         For Each mo As ManagementObject In processCollection
            KillProcessAndChildrens(Convert.ToInt32(mo.Item("ProcessID")))
         Next
      End If

      '    // Then kill parents.
      Try
         Dim proc As Process = Process.GetProcessById(pintPID)
         If Not proc.HasExited Then
            proc.Kill()
         End If

      Catch ex As Exception
         '         Process already exited.
      End Try
   End Sub

答案 3 :(得分:0)

process.Kill()正在运行,而不是你想到的过程。你正在做的是实际启动2个进程,只杀死第一个进程,而第二个进程继续运行。 您拥有的代码是启动一个新的命令shell并将该进程信息保存到process。当您调用process.Kill()时,只有命令shell退出您可以运行

Console.WriteLine(process.ProcessName);

在你process.Kill()之前看看哪个进程实际上会被杀死。通过将\c ping -t 8.8.8.8设置为命令shell的参数,您将告诉命令shell启动另一个进程(在本例中为ping)并将其与自身分离。您的程序不了解子进程,也不会杀死它。如果您真正想要的是杀死ping过程,您可以将代码更改为:

Console.WriteLine("Total number of ping processes is {0}",  Process.GetProcessesByName("ping").Length);

ProcessStartInfo startInfo = new ProcessStartInfo("ping");
Process process = new Process();

startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = "-t 8.8.8.8";

Console.WriteLine("Staring ping process");
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);
Thread.Sleep(5000);

Console.WriteLine("Killing ping process");
process.Kill();
Thread.Sleep(5000);

Console.WriteLine("Total number of ping processes is {0}", Process.GetProcessesByName("ping").Length);

但是,如果你真的需要首先启动命令shell,你需要找到子进程并有逻辑来杀死它。类似的东西:

foreach( var p in Process.GetProcessesByName("ping"))
{
  p.Kill();
}

[编辑] *抱歉,我最初没有看到@Adriano Repetti的评论。我不是故意多余的。

答案 4 :(得分:-1)

  

要杀死进程,您必须在管理下运行   帐户。这意味着要么你是真的'管理员或你   用户帐户控制(UAC)已关闭。

     

否则Process.Kill()将失败。

来自here