Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does process.kill() terminate the WaitForExit() (with no time limit)

Tags:

c#

process

I have a process that runs in the background and has WaitForExit(), since the duration may vary and I need to wait till it finishes. On occasions, I need to end it before it completes and I trigger .Kill() command via a class event. The .HasExited property changes to true but the code never gets passed the WaitForExit() line.

public class MyProcess: Process
{
    private bool exited;

    public MyProcess()
    {
            ...
    }




    public void Start(args...)
    {

            try
            {
                base.StartInfo.FileName = ...
                base.StartInfo.Arguments = ...
                base.StartInfo.RedirectStandardOutput = true;
                base.StartInfo.UseShellExecute = false;
                base.StartInfo.CreateNoWindow = true;
                base.EnableRaisingEvents = true;
                base.Exited += new EventHandler(MyProcessCompleted);
                base.OutputDataReceived += new DataReceivedEventHandler(outputReceived);
                base.Start();
                this.exited = false;
                base.BeginOutputReadLine();

                    while (!this.exited)
                    {
                      if ()
                        {
                       ...
                        }
                       else
                       {

                    base.WaitForExit(); ---- after the process is killed, it never gets past this line.

                       }

                    ...                    
                }
            }

            catch (Exception ex)
            {
                ...                
             }
        }


    private void MyProcessCompleted(object sender, System.EventArgs e)
    {
        exited = true;

        ...  
    }


    private void outputReceived(object sender, DataReceivedEventArgs e)
    {
           ...
     }


  //Subscription to cancel event
    public void ProcessCanceled(object sender, EventArgs e)
    {
        ...

        if (!exited)
        {
            base.Kill();
        }
    }
}

\

UPDATE:

My process launches a java based file transfer client and performs a transfer. The process shows up in the task manager and Kill() does not end it. Since I don't really care about ending the process but rather need my program to go to the next "task", I added Close() right after Kill(), which releases the WaitForExit and lets my code "move on". Terminating the process early will be a rare occurance in my app, but I still need it to work, so this implementation will have to do.

}

like image 555
Felix Avatar asked Sep 09 '13 21:09

Felix


1 Answers

WaitForExit is a direct call to the OS to wait for the process handle to become signaled. When a process terminates, WaitForExit will complete. Kill is a direct call to TerminateProcess which is a kill with no questions asked. If used correctly WaitForExit will return after Kill has completed.

So there is some other bug in your code. Create a simpler repro and you will see the issue disappear. The bug is hidden in the complexity of your code.

Or, WaitForExit did return but you did not notice. Or, Kill was never executed or failed. Again, simplifying the code will reveal the issue. Can you bring it down to a 5 line repro? I doubt you can, but I will look again if you do.

Try this:

Process p = Process.Start("notepad.exe");
Task.Factory.StartNew(() => { Thread.Sleep(1000); p.Kill(); });
p.WaitForExit();

Update:

In the comments you specified that killing ping does work, but killing your special process doesn't. The cause for this usually is non-cancellable IO. The Windows kernel keeps processes around until all IO is done. The good news is that the process will die eventually and no code will run after Kill has returned. The bad news is that resource cleanup is not fully completed.

You now need to ensure that your code can move on although WaitForExit did not return. To do that I'd set a ManualResetEvent after Kill has completed. And instead of calling WaitForExit, you obtain the process handle using the Process.Handle property and wait on either of the two waitables to become signaled. Look at what WaitForExit does internally to see how you could implement this yourself (I'd copy out the ProcessWaitHandle class which is internal).

A simpler solution would be to call WaitForExit(TimeSpan.FromMilliseconds(100)) in a loop and check the exited flag each time.

like image 196
usr Avatar answered Nov 10 '22 20:11

usr