Process.Kill() doesn't seem to kill the proces

2020-05-19 08:31发布

I am having trouble using Process.Kill(). I think I must be misunderstanding how it works. This is my test function. I start a long-running process (ping -t) and then kill it five seconds later.

I can see the ping process show up, but the process is still there after my program finishes. I have to kill it manually.

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);

What am I doing wrong here?

4条回答
霸刀☆藐视天下
2楼-- · 2020-05-19 08:59

process.Kill() is working, just not on the process you think. What you're doing is actually starting 2 processes and only killing the first process, while the second process keeps running. The code you have is starting a new command shell and saving that process info to process. When you call process.Kill() only the command shell is exiting You can run

Console.WriteLine(process.ProcessName);

before you process.Kill() to see which process is actually going to be killed. By setting \c ping -t 8.8.8.8 as arguments to the command shell, you're telling the command shell to start another process (in this case ping) and disjoin it from itself. Your program has no knowledge about the child process and will not kill it. If all you really want is to kill the ping process you can change your code to:

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);

If, however, you really need to start the command shell first you'll need to find the child processes and have logic to kill that. Something like:

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

[EDIT] *Sorry, I didn't see the comments from @Adriano Repetti at first. I didn't mean to be redundant.

查看更多
Rolldiameter
3楼-- · 2020-05-19 09:00

You started cmd.exe, then cmd.exe starts child process ping.exe. To kill ping.exe you can kill all process hierarchy. For example with WMI(add System.Management reference):

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.)
        }
    }
}
查看更多
叛逆
4楼-- · 2020-05-19 09:12

This is a patch for the @SulNR answer since its answer leak child processes of child processes.

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.
    }
}
查看更多
smile是对你的礼貌
5楼-- · 2020-05-19 09:16

In order to kill a process you have to run under an administrative account. This means either that you are a 'true' administrator or you User Account Control (UAC) turned off.

Otherwise Process.Kill() will fail.

From here.

查看更多
登录 后发表回答