web-dev-qa-db-ja.com

Process.Kill()はプロセスを強制終了しないようです

Process.Kill()を使用できません。私はそれがどのように機能するかを誤解しているに違いないと思います。これは私のテスト関数です。長期実行プロセスを開始します(ping -t)そして5秒後にそれを殺します。

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

ここで何が悪いのですか?

16
Kris Harper

Cmd.exeを起動してから、cmd.exeが子プロセスping.exeを起動します。 ping.exeを強制終了するには、すべてのプロセス階層を強制終了できます。たとえば、WMI(add 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.)
        }
    }
}
21
SulNR

これは @ 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.
    }
}
6
Julio

process.Kill()は、あなたが考えているプロセスではなく、機能しています。あなたがやっていることは、実際には2つのプロセスを開始し、最初のプロセスのみを殺すことですが、2番目のプロセスは実行を続けます。あなたが持っているコードは、新しいコマンドShellを開始し、そのプロセス情報をprocessに保存しています。 process.Kill()を呼び出すと、シェルが終了するコマンドのみが実行されます

_Console.WriteLine(process.ProcessName);
_

process.Kill()を実行する前に、実際に強制終了されるプロセスを確認してください。コマンドシェルの引数として_\c ping -t 8.8.8.8_を設定することで、コマンドシェルに別のプロセス(この場合は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からのコメントは最初は表示されませんでした。冗長であるという意味ではありませんでした。

0
rogergarrison