17

タスク:親プロセスが終了した場合、すべての子プロセスを自動的に強制終了します。親プロセスは、正しい方法だけでなく、たとえば ProcessExplorer で強制終了することによっても終了できます。どうすればいいですか?

Job オブジェクトを使用するためのСtopicのアドバイスの同様の質問。外部DLLをエクスポートせずにC#で使用するには?


ジョブ オブジェクトを使用しようとしました。しかし、このコードは正しく動作しません:

  var job = PInvoke.CreateJobObject(null, null);
  var jobli = new PInvoke.JOBOBJECT_BASIC_LIMIT_INFORMATION();

  jobli.LimitFlags = PInvoke.LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
                   | PInvoke.LimitFlags.JOB_OBJECT_LIMIT_PRIORITY_CLASS
                   | PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_TIME
                   | PInvoke.LimitFlags.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
                   | PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_MEMORY;

  var res = PInvoke.SetInformationJobObject(job, PInvoke.JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation, jobli, 48);

  if (!res)
  {
    int b = PInvoke.GetLastError();
    Console.WriteLine("Error " + b);
  }

  var Prc = Process.Start(...);

  PInvoke.AssignProcessToJobObject(job, Prc.Handle);

PInvoke.SetInformationJobObject がエラーを返します。GetLastError はエラー 24 を返します。ただし、PInvoke.AssignProcessToJobObject は機能し、子プロセスがジョブ キューに追加されます (ProcessExplorer で確認できます)。しかし、 PInvoke.SetInformationJobObject が機能しないため、親プロセスを強制終了しても、生成されたプロセスは存続します。

このコードの何が間違っていますか?

4

5 に答える 5

9

上記のコードを試してみましたが、実際には機能せず、サイズが悪いと不平を言っています。これは、ホスト プラットフォームによって使用される構造体のサイズが変わるためです。元のコード フラグメント (多数の Web サイトで見られる) は、32 ビット アプリケーションを前提としています。

構造をこれに切り替えると (IntPtr のサイズ変更メンバーに注意してください)、機能します。少なくとも私にはそうでした。

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
    public Int64 PerProcessUserTimeLimit;
    public Int64 PerJobUserTimeLimit;
    public Int16 LimitFlags;
    public UIntPtr MinimumWorkingSetSize;
    public UIntPtr MaximumWorkingSetSize;
    public Int16 ActiveProcessLimit;
    public Int64 Affinity;
    public Int16 PriorityClass;
    public Int16 SchedulingClass;
}
于 2011-05-12T09:46:37.693 に答える
9

Windows でプロセス ツリーを強制終了するには、親プロセスまたはプロセス ID のみを指定して、プロセス ツリーをたどる必要があります。

そのためには、特定のプロセスの親プロセス ID を取得する方法が必要です。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Management;

namespace KillProcessTree
{

public static class MyExtensions
{
    public static int GetParentProcessId(this Process p)
    {
        int parentId = 0;
        try
        {
            ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
            mo.Get();
            parentId = Convert.ToInt32(mo["ParentProcessId"]);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            parentId = 0;
        }
        return parentId;
    }
}

それができたら、実際に木を殺すのは難しくありません。

class Program
{
    /// <summary>
    /// Kill specified process and all child processes
    /// </summary>
    static void Main(string[] args)
    {
        if (args.Length < 1)
        {
            Console.WriteLine("Usage: KillProcessTree <pid>");
            return;
        }

        int pid = int.Parse(args[0]);

        Process root = Process.GetProcessById(pid);
        if (root != null)
        {
            Console.WriteLine("KillProcessTree " + pid);

            var list = new List<Process>();
            GetProcessAndChildren(Process.GetProcesses(), root, list, 1);

            // kill each process
            foreach (Process p in list)
            {
                try
                {
                    p.Kill();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
        else
        {
            Console.WriteLine("Unknown process id: " + root);
        }
    }

    /// <summary>
    /// Get process and children
    /// We use postorder (bottom up) traversal; good as any when you kill a process tree </summary>
    /// </summary>
    /// <param name="plist">Array of all processes</param>
    /// <param name="parent">Parent process</param>
    /// <param name="output">Output list</param>
    /// <param name="indent">Indent level</param>
    private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
    {
        foreach (Process p in plist)
        {
            if (p.GetParentProcessId() == parent.Id)
            {
                GetProcessAndChildren(plist, p, output, indent + 1);
            }
        }
        output.Add(parent);
        Console.WriteLine(String.Format("{0," + indent*4 + "} {1}", parent.Id, parent.MainModule.ModuleName));
    }
}
} // namespace
于 2011-04-15T17:08:02.503 に答える
4

ProcessID親プロセスを引数として子プロセスに渡すことができます。そして、子プロセスは、親プロセスがまだ実行されているかどうかを時々チェックする責任があります。(電話でProcess.GetProcessById。)

親プロセスの存在を追跡する別の方法は、Mutex同期プリミティブを使用することです。親アプリケーションは、最初に、子に知られている名前でグローバル ミューテックスを作成します。子プロセスは、ミューテックスがまだ存在するかどうかを時々確認し、存在しない場合は終了できます。(親プロセスが閉じられると、閉じた方法に関係なく、ミューテックスはシステムによって自動的に破棄されます。)

于 2010-07-13T09:00:59.870 に答える
3

エラーコードに注意しましたか?エラー 24 は ですERROR_BAD_LENGTH。これはおそらく、48 が構造体の正しい長さではないことを意味します。44 だと思いますが、sizeof念のために a を実行する必要があります。

于 2010-07-22T12:18:42.413 に答える
2

Windows は、親プロセスが閉じられたときに子プロセスを強制的に閉じません。タスク マネージャーやプロセス エクスプローラーなどのツールで [Kill Tree] を選択すると、ツールは実際にすべての子プロセスを見つけて、1 つずつ強制終了します。

アプリケーションの終了時に子プロセスが確実に消去されるようにする場合は、実際にプロセスを作成し、それらのインスタンスを追跡し、Dispose でそれらのそれぞれに対して Kill を呼び出す IDisposable を実装する ProcessManager クラスを作成できます。

public class ProcessManager:IDisposable
{
    List<Process> processes=new List<Process>();

    public Process Start(ProcessStartInfo info)
    {
        var newProcess = Process.Start(info);
        newProcess.EnableRaisingEvents = true
        processes.Add(newProcess);
        newProcess.Exited += (sender, e) => processes.Remove(newProcess);
        return newProcess;
    }

    ~ProcessManager()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        foreach (var process in processes)
        {
            try
            {
                if (!process.HasExited)
                    process.Kill();
            }
            catch{}                    
        }
    }
}
于 2010-07-13T09:35:25.417 に答える