2009-03-10 16 views
7

Temel olarak alt işlem, arka planda ölene kadar süresiz olarak çalışır ve programım herhangi bir nedenle, yani Görev Yöneticisi aracılığıyla sona erdiğinde, temizlemek istiyorum.Programım tarafından ortaya çıkarılan bir arkaplan sürecinin sürecim sona erdiğinde öldürülmesini sağlamanın bir yolu var mı?

Şimdilik bir sürem var (Process.GetProcessesByName ("ParentProcess"). Count()> 0) döngü ve ana işlem çalışmıyorsa çıkın, ancak oldukça kırılgan görünüyor ve eğer çalışmak istiyorsam Visual Studio'da hata ayıklayıcı altında "ParentProcess.vshost" veya bir şey eklemek zorunda kaldım.

Çocuk işleminin, ana işlem hakkında bilgi sahibi olmasını gerektirmeden, alt işlemin sonlandırıldığından emin olmanın bir yolu var mı? Yönetilen kodda bir çözümü tercih ederim ama eğer biri değilse PInvoke yapabilirim.

Düzenleme: PID'yi geçmek daha sağlam bir çözüm gibi gözüküyor, ancak merakı hatırlatmak istersek, çocuk süreç benim kodum değilse de kontrolüm olmayan bazı exe'larsa ne olurdu? Öksüz çocuk süreçlerinin yaratılmasına karşı korunmanın bir yolu var mı?

cevap

7

Çocuk işlemi kendi kodunuzsa, başlattığınızda ana işlemin PID'sini geçirebilirsiniz. Çocuk işlemi daha sonra işlemi Process.GetProcessById ile getirebilir ve Exited olayına geri kalan (çocuk) sürecini hassas bir şekilde kapatan bir işleyiciye abone olabilir. İşlemle ilgili EnableRaisingEvents özelliğini true olarak ayarlamanız gerektiğini unutmayın.

3

orphan process gibi bir alt işlem için ortak terim. Bazı olası çözümler için bağlantılı makaleye bakın.

0

Ana işlem kimliğini komut satırı parametresi olarak çocuk işlemine geçirin.

çocuk süreç Kullanımda kimliğiyle Süreci almak ve Çıkış etkinliği var abone olmak veya bir iş parçacığı oluşturmak ve alt süreç kendi kod bulup öldürmek için bu kodu kullanabilirsiniz değilse

5

Process.WaitForExit çağrısı tüm alt süreçler:

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 

namespace Util { 
    public static class ProcessExtensions { 
     public static void KillDescendants(this Process processToNotKillYet) { 
      foreach (var eachProcess in Process.GetProcesses()) { 
       if (eachProcess.ParentPid() == processToNotKillYet.Id) { 
        eachProcess.KillTree(); 
       } 
      } 
     } 

     public static void KillTree(this Process processToKill) { 
      processToKill.KillDescendants(); 
      processToKill.Kill(); 
     } 

     public static PROCESS_BASIC_INFORMATION Info(this Process process) { 
      var processInfo = new PROCESS_BASIC_INFORMATION(); 
      try { 
       uint bytesWritten; 
       NtQueryInformationProcess(process.Handle, 
              0, 
              ref processInfo, 
              (uint)Marshal.SizeOf(processInfo), 
              out bytesWritten); // == 0 is OK 
      } 
      catch (Win32Exception e) { 
       if (!e.Message.Equals("Access is denied")) throw; 
      } 

      return processInfo; 
     } 

     public static int ParentPid(this Process process) { 
      return process.Info().ParentPid; 
     } 

     [DllImport("ntdll.dll")] 
     private static extern int NtQueryInformationProcess(
      IntPtr hProcess, 
      int processInformationClass /* 0 */, 
      ref PROCESS_BASIC_INFORMATION processBasicInformation, 
      uint processInformationLength, 
      out uint returnLength); 

     [StructLayout(LayoutKind.Sequential)] 
     public struct PROCESS_BASIC_INFORMATION { 
      public int ExitStatus; 
      public int PebBaseAddress; 
      public int AffinityMask; 
      public int BasePriority; 
      public int Pid; 
      public int ParentPid; 
     } 
    } 
} 
+0

da kontrol dışarı farklı bir yaklaşımla bazı kısa kod için bu cevap: http://stackoverflow.com/a/7189381/177710. – Oliver

1

Burada (ben oldukça yararlı buldum Alan Hensel çözümü dayanmaktadır) inşa edilmiş küçük bir yardımcı programdır uygulama için kaynak kodu.

O ChildrenProcessKiller denir ve üst süreç çıkışları (ana süreç çöküyor bile) ne zaman belirli bir ebeveyn sürecinin bütün torunları sürecini öldürmeye sağlayan bir izleyici mesafesindedir

Kullanımı:

ChildrenProcessKiller.exe parentProcessId 

Uyarı: "olduğu gibi" bu kod sağlanır ve küçük bebeklerin ;-)

ChildrenProcessKiller.cs öldürebilir

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 

namespace ChildrenProcessKiller 
{ 
    static class ChildrenProcessKiller 
    { 
    [STAThread] 
    static void Main(string[] args) 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 

     string message = "This is a watcher that enables to kill all descendants process of a given parent process\n"; 
     message += "when the parent process exits (even if the parent process crashes) \n\n"; 
     message += "Usage : " + Application.ExecutablePath + " parentProcessId"; 

     if (args.Length != 1) 
     { 
     MessageBox.Show(message); 
     System.Environment.Exit(1); 
     } 

     int parentProcessId; 
     if (!Int32.TryParse(args[0], out parentProcessId)) 
     { 
     MessageBox.Show(message); 
     System.Environment.Exit(1); 
     } 

     try 
     { 
     mParentProcess = Process.GetProcessById(parentProcessId); 
     } 
     catch (System.ArgumentException ex) 
     { 
     //Parent process cannot be found! 
     System.Environment.Exit(2); 
     } 
     Run(); 
    } 

    private static List<Process> mChildrenProcesses; 
    private static Process mParentProcess; 

    private static void Run() 
    { 
     int thisProcessId = Process.GetCurrentProcess().Id; 
     while (! mParentProcess.HasExited) 
     { 
     RefreshChildrenProcesses(); 
     System.Threading.Thread.Sleep(1000); 
     } 

     foreach (Process childProcess in mChildrenProcesses) 
     { 
     if ((!childProcess.HasExited) && (childProcess.Id != thisProcessId)) 
     { 
      KillGracefullyThenViolently(childProcess); 
     } 
     } 
    } 

    private static void KillGracefullyThenViolently(Process process) 
    { 
     if (process.HasExited) 
     return; 

     try 
     { 
     process.CloseMainWindow(); 
     } 
     catch (PlatformNotSupportedException) 
     {} 
     catch (InvalidOperationException) 
     {}//do nothing : this app is meant to be "unstoppable", unless the parent process has exited 

     for (int i = 0; i < 15; i++) 
     { 
     System.Threading.Thread.Sleep(100); 
     if (process.HasExited) 
      return; 
     } 

     try 
     { 
     process.Kill(); 
     } 
     catch (System.ComponentModel.Win32Exception) 
     {} 
     catch(NotSupportedException) 
     {} 
     catch(InvalidOperationException) 
     {} //same comment here 
    } 

    private static void RefreshChildrenProcesses() 
    { 
     if (mParentProcess.HasExited) 
     return; 
     List<Process> newChildren; 
     try 
     { 
     newChildren = Utils.ProcessTree.GetProcessDescendants(mParentProcess); 
     mChildrenProcesses = newChildren; 
     } 
     catch (System.Exception ex) 
     { 
     ; 
     } 
    } 


    } 
} 

ProcessTree.cs

using System; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Collections.Generic; 
using System.IO; 
using System.Windows.Forms; 

namespace Utils 
{ 
    public static class ProcessTree 
    { 

    public static List<Process> GetProcessDescendants(Process process) 
    { 
     List<Process> result = new List<Process>(); 
     foreach (Process eachProcess in Process.GetProcesses()) 
     { 
     if (ParentPid(eachProcess) == process.Id) 
     { 
      result.Add(eachProcess); 
     } 
     } 
     return result; 
    } 

    public static void KillDescendants(Process processToNotKillYet) 
    { 
     foreach (Process eachProcess in Process.GetProcesses()) 
     { 
     if (ParentPid(eachProcess) == processToNotKillYet.Id) 
     { 
      if (eachProcess.Id != Process.GetCurrentProcess().Id) 
      KillTree(eachProcess); 
     } 
     } 
    } 

    public static void KillTree(Process processToKill) 
    { 
     KillDescendants(processToKill); 
     processToKill.Kill(); 
    } 

    public static PROCESS_BASIC_INFORMATION Info(Process process) 
    { 
     PROCESS_BASIC_INFORMATION processInfo = new PROCESS_BASIC_INFORMATION(); 
     try 
     { 
     uint bytesWritten; 
     NtQueryInformationProcess(process.Handle, 
         0, 
         ref processInfo, 
         (uint)Marshal.SizeOf(processInfo), 
         out bytesWritten); // == 0 is OK 
     } 
     catch (Win32Exception e) 
     { 
     if (!e.Message.Equals("Access is denied")) throw; 
     } 

     return processInfo; 
    } 

    public static int ParentPid(Process process) 
    { 
     return Info(process).ParentPid; 
    } 

    [DllImport("ntdll.dll")] 
    private static extern int NtQueryInformationProcess(
     IntPtr hProcess, 
     int processInformationClass /* 0 */, 
     ref PROCESS_BASIC_INFORMATION processBasicInformation, 
     uint processInformationLength, 
     out uint returnLength); 

    [StructLayout(LayoutKind.Sequential)] 
    public struct PROCESS_BASIC_INFORMATION 
    { 
     public int ExitStatus; 
     public int PebBaseAddress; 
     public int AffinityMask; 
     public int BasePriority; 
     public int Pid; 
     public int ParentPid; 
    } 
    } 
} 
İlgili konular