My Blog

Job Objects (Windows)

by lupok on lunedì 11 febbraio 2013 22:28
Immaginate di voler attendere 2 minuti per un completamento di un processo, se si ha il controllo del processo figlio è sufficiente eseguirlo in background ed eseguire un controllo ad ogni secondo per vedere se è terminato. In questo modo si possono creare alberi di processi in cui il processo padre ha pieno controllo dei processi figli ed alla terminazione dello stesso anche tutti i processi figli vengono terminati evitando la proliferazione di processi "zombie". Per creare un job object occorre utilizzare la funzione CreateJobObject ed una volta creato non dispone di alcun processo ad esso associato, per associare un processo ad un job utilizzare la funzione AssignProcessToJobObject. Un processo associato ad un job non può più essere separato da esso, ma un processo può essere associato a più di un job in una gerarchia dei processi annidati. Nell'esempio mostrato di seguito è presente un'applicazione console che crea un job a cui vengono associati diversi processi (per semplicità una serie di processi Notepad):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ProcessJobs
{
   class Program
   {
      static void Main(string[] args)
      {
         var job = Job.CreateOrOpen("HOST");
 
         for (int i = 0; i < 5; i++)
         {
            using (var proc = System.Diagnostics.Process.Start("notepad.exe"))
               job.AddProcess(proc);
         }
 
         Console.WriteLine("Press ENTER to terminate job...");
         Console.ReadLine();
 
         job.Ternimate(0);
 
      }
   }
 
   public class Job
   {
      [System.Runtime.InteropServices.StructLayout(
         System.Runtime.InteropServices.LayoutKind.Sequential)]
      internal struct SECURITY_ATTRIBUTES
      {
         public int nLength;
         public IntPtr lpSecurityDescriptor;
         public int bInheritHandle;
      }
 
      [System.Runtime.InteropServices.DllImport("kernel32.dll",
         CharSet = System.Runtime.InteropServices.CharSet.Unicode, SetLastError = true)]
      static extern IntPtr CreateJobObject(SECURITY_ATTRIBUTES attributes, String name);
 
      [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
      static extern Boolean AssignProcessToJobObject(IntPtr job, IntPtr process);
 
      [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
      static extern Boolean TerminateJobObject(IntPtr job, UInt32 exitCode);
 
      private IntPtr _handle;
 
      public Job(IntPtr handle)
      {
         _handle = handle;
      }
 
      public static Job CreateOrOpen(String name)
      {
         var res = CreateJobObject(new SECURITY_ATTRIBUTES(), name);
         if (res == IntPtr.Zero)
            throw new System.ComponentModel.Win32Exception();
 
         return new Job(res);
      }
 
      public void AddProcess(System.Diagnostics.Process process)
      {
         if (!AssignProcessToJobObject(_handle, process.Handle))
            throw new System.ComponentModel.Win32Exception();
      }
 
      public void Ternimate(UInt32 exitCode)
      {
         if (!TerminateJobObject(_handle, exitCode))
            throw new System.ComponentModel.Win32Exception();
      }
   }
}

Se utilizziamo ProcessXP per visualizzare la lista dei processi attivi nel sistema, noteremo che i processi notepad vengono rappresentati con nodi di un processo padre che è l'applicazione creata:

 

L'applicazione deve essere eseguita esternamente a Visual Studio, in quanto per motivi di sicurezza genererebbe un'eccezione di Accesso Negato. 

ProcessJobs.zip

Il programma puo' essere anche modificato nel seguente modo: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProcessJobs
{
   class Program
   {
      static void Main(string[] args)
      {
         var job = Job.CreateOrOpen("HOST");

         var proc = System.Diagnostics.Process.GetCurrentProcess();

         job.AddProcess(proc);

         for (int i = 0; i < 5; i++)
         {
            System.Diagnostics.Process.Start("notepad.exe");
         }

         Console.WriteLine("Press ENTER to terminate job...");
         Console.ReadLine();

         job.Ternimate(0);

      }
   }
}


 

Come si vede il processo assegnato al job e' quello corrente, in questo caso ogni processo che viene creato e' un processo flglio a meno che non venga specificato il flag CREATE_BREAKAWAY_FROM_JOB nella CreateProcess (https://msdn.microsoft.com/it-it/library/windows/desktop/ms681949(v=vs.85).aspx)

 

Blogs Parent Separator My Blog
Author
lupok

My Blog

1 comment(s) so far...

lupok 28/07/2017

Il programma puo' essere anche modificato nel seguente modo: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProcessJobs { class Program { static void Main(string[] args) { var job = Job.CreateOrOpen("HOST"); var proc = System.Diagnostics.Process.GetCurrentProcess(); job.AddProcess(proc); for (int i = 0; i < 5; i++) { System.Diagnostics.Process.Start("notepad.exe"); } Console.WriteLine("Press ENTER to terminate job..."); Console.ReadLine(); job.Ternimate(0); } } } Come si vede il processo assegnato al job e' quello corrente, in questo caso ogni processo che viene creato e' un processo flglio a meno che non venga specificato il flag CREATE_BREAKAWAY_FROM_JOB nella CreateProcess (https://msdn.microsoft.com/it-it/library/windows/desktop/ms681949(v=vs.85).aspx)

Tags