4

The issue: I am having an issue where I cannot immediately stop a batch file running inside an C# app (process) by using processName.Kill()

In my project, the batch file will run several python scripts, taking around 30 minutes to complete in total. It will sporadically dump several lines of output to console, which I am capturing using the associated process' standard output.

I am setting up and starting the process like so:

var process = new Process
{
    StartInfo = new ProcessStartInfo
    {
        UseShellExecute = false,
        FileName = @"C:\Test.bat",
        WorkingDirectory = @"C:\",
        RedirectStandardOutput = true,  
    },
}; 
process.Start();

The batch file that I am testing with is extremely simple:

echo starting
timeout /t 4
echo it worked

I am using a cancellation token from a shared cancellation token source and cancelling after 2000 seconds. I have attached the following event to the token:

ct.Register(() =>
{
    process.Kill();
});

I am sending the standardOutput to a blocking collection of strings line by line like so:

Task.Factory.StartNew(() =>
{
    while (!streamReader.EndOfStream)
    {
        var line = streamReader.ReadLine();

        if (line == null) break;

        _blockingCollection.Add(line);
    }

    _blockingCollection.CompleteAdding();
});

What I expect to happen: because the process has been killed by the event raised by the cancellation token, I would expect the streamReader.Readline() method to either immediately return null or throw an exception. Instead, it waits for the timeout in the batch file to complete and then returns the full line that the timeout prints. In my real application, it could be waiting for 10-15 minutes for the next output from the scripts.

Am I misunderstanding how process.Kill() works? Is it that timeout behaves oddly? In an ideal situation, I would like the stream reader to immediately stop reading and break out of the while loop.

I tried doing this by having an event raised every time the process output received new data however I could not synchronize these to run in the right order as the scripts had a tendency to dump several hundred of lines of output at the same time

Thanks

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Alex23
  • 401
  • 4
  • 8
  • 4
    You misunderstand how .bat files work There is more than one process to Kill(). The command processor (cmd.exe) that's executing the .bat file, you hit that one. But not the process that's executing the timeout, timeout.exe. There is in general no 100% reliable way to discover and timely kill any processes started by a .bat file. You might get ahead [with this](http://stackoverflow.com/a/2533287/17034) but it is a race. – Hans Passant Nov 30 '16 at 13:13
  • is there a way I can kill the process in the same way that ctrl+c does inside the command window? – Alex23 Nov 30 '16 at 13:56
  • Instead of use `process.Kill`, try to feed a Ctrl-C (Ascii 3) followed by `Y\n` to the stdin of the .bat (cmd.exe) file. – Aacini Nov 30 '16 at 16:28

1 Answers1

0

(Sorry I can't comment.)

I guess it is because the command: timeout is troubling here. I once tried to kill a timeouting batch with Command Prompt and it happens as same as above. The batch wouldn't be able to be terminated until the timeouting has finished.

Maybe you can try for Process.Kill("timeout.exe") after killing the batch.


Sorry if I am misunderstanding your question. I'm just a newbie here.