it-swarm.com.de

Process.Kill () scheint den Prozess nicht zu beenden

Ich habe Probleme mit Process.Kill(). Ich denke, ich muss falsch verstehen, wie es funktioniert. Dies ist meine Testfunktion. Ich starte einen lang laufenden Prozess (ping -t) und bringe ihn fünf Sekunden später ab.

Ich kann den Ping-Prozess sehen, aber der Prozess ist immer noch da, nachdem mein Programm beendet ist. Ich muss es manuell töten.

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

Was mache ich hier falsch?

12
Kris Harper

Sie haben cmd.exe gestartet, dann startet cmd.exe den untergeordneten Prozess ping.exe. Um ping.exe zu beenden, können Sie die gesamte Prozesshierarchie beenden. Zum Beispiel mit 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.)
        }
    }
}
16
SulNR

Dies ist ein Patch für die Antwort " @SulNR ", da die untergeordneten Prozesse von untergeordneten Prozessen unterlaufen werden.

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.
    }
}
3
Julio

process.Kill () funktioniert, nur nicht in dem Prozess, den Sie denken. Sie starten tatsächlich zwei Prozesse und beenden nur den ersten Prozess, während der zweite Prozess weiterläuft. Der Code, den Sie haben, startet eine neue Befehlsshell und speichert diese Prozessinformationen in process. Wenn Sie process.Kill() aufrufen, wird nur der Befehl Shell beendet, den Sie ausführen können 

Console.WriteLine(process.ProcessName);

bevor Sie process.Kill() sehen, welcher Prozess tatsächlich beendet wird. Durch Festlegen von \c ping -t 8.8.8.8 als Argumente für den Befehl Shell fordern Sie den Befehl Shell auf, einen anderen Prozess zu starten (in diesem Fall Ping) und ihn von sich zu trennen. Ihr Programm hat kein Wissen über den Kindprozess und wird es nicht töten. Wenn Sie wirklich nur den Ping-Prozess beenden möchten, können Sie Ihren Code folgendermaßen ändern:

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

Wenn Sie jedoch wirklich zuerst den Befehl Shell starten müssen, müssen Sie die untergeordneten Prozesse finden und über Logik verfügen, um dies zu beenden. So etwas wie:

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

[EDIT] * Entschuldigung, ich habe die Kommentare von @Adriano Repetti zunächst nicht gesehen. Ich wollte nicht überflüssig sein.

0
rogergarrison