views:

185

answers:

5

Task: Auto kill all child processes if parent process terminate. Parent procees can be terminated not only in correct way, but also by killing in ProcessExplorer, for example. How can I do it?

Similar question in С topic advice to use Job objects. How to use it in C# without exporting external DLL?


I tried to use Job Objects. But this code don't work properly:

  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 returns with error. GetLastError returns error 24. However, PInvoke.AssignProcessToJobObject works and child process added to Job Queue (I can see it in ProcessExplorer). But, because PInvoke.SetInformationJobObject don't work - spawned process stay alive when I kill parent one.

What do I incorrect in this code?

A: 

You could use the System.Diagnostics.Process class to get a hold of your child process (GetProcess() method) and when closing your parent app, call process.kill

System.Diagnostics.Process proc = (System.Diagnostics.Process.GetProcessesByName("MyProcess")[0]);
            proc.Kill();

The above gets the first item in the list (asuming you know the name of your process) and kills it (you may want to do a check that the list returned doesn't contain more than one process just in case you kill something accidentaly).

Ben
I know how to kill child processes **manually**, but I need that child processes will be killed **anyway** *by OS*. *For example, I open ProcessExplorer and kill my parent process - I want that all CP will be killed too.*
LionSoft
A: 

If I understand your question corectly and your talking about a Thread you want to automatically kill, you can set the threads IsBackground property to true.

When you set the property it basically means "Dont wait for this thread to complete when the program closes down" and should kill any thread related to a process when its killed.

Example:

class Program
{
    static void Main(string[] args)
    {
        Thread myThread = new Thread(doWork);
        myThread.IsBackground = true;
        myThread.Start();

        Console.Read();
    }

    public static void doWork()
    {
        while (true)
        {
            Console.WriteLine("myThread Doing Work");
            Thread.Sleep(200);
        }
    }
}
HarveySaayman
No. I talking about **child processes** (Process.Start(PSI)) not the threads.
LionSoft
Ah okay, never mind me then ;-)
HarveySaayman
+1  A: 

You can pass ProcessID of the parent process as an argument to the child process. And then child processes will be responsible for checking from time to time whether the parent process still running. (By calling Process.GetProcessById.)

Another way to track existence of the parent process is to use Mutex synchronization primitive. Parent application will initially create a global mutex with the name known by children. Children can check from time to time whether the mutex still exists and terminate if not. (Once the parent process is closed the mutex will be destroyed by the system automatically, regardless of the way it way closed.)

Regent
Both advices doesn't usefull - child processes are not mine. They can be any programs.
LionSoft
@LionSoft: Can you have another child process which will be responsible for creating those child processes? Then that process can check whether the parent process is still running and kill other children if not.
Regent
But what to do if that "another child process" will be forced terminated?
LionSoft
@LionSoft: You can recreate it again by the parent process. So if the parent process gets killed then child-manager process will kill other children and quit; but if the child-manager is killed, then the parent process will create it again.
Regent
A: 

Windows does not force child processes to close when a parent process closes. When you select "Kill Tree" in a tool like Task Manager or Process explorer, the tool actually finds all child processes and kill them one by one.

If you want to ensure that child processes are cleaned when your application terminates, you can create a ProcessManager class that implements IDisposable that actually creates the processes, keeps track of their instances and calls Kill on each one of them on Dispose, e.g.

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{}                    
        }
    }
}
Panagiotis Kanavos
Unfortunately, when I hardly kill process in ProcessExplorer the process have no chance to do finalization code. So, your exaple will be work only when parent process terminate correctly.BTW, to correct work your example, it have to add line **newProcess.EnableRaisingEvents = true;** before assigning *Exiting* event.
LionSoft
As I said, Windows just does not kill child processes when a parent process dies. There is no OS mechanism to enforce that. A child proces does NOT belong to its parent. If you want to spawn processing jobs that are guaranteed to be cleaned when a process dies, you have to use threads.You are right about EnableRaisingEvents, fixed it.
Panagiotis Kanavos
There are at least two OS mechanisms to kill spawned processes:1. Attach to child process as debugger.2. Use Job Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flagBut I can't work both this methods so far. :(
LionSoft
+1  A: 

Did you pay attention to the error code? Error 24 is ERROR_BAD_LENGTH, which probably means that 48 isn't the right length of the structure. I think it's 44, but you should do a sizeof to be sure.

Gabe