6

I have application that launches sub process and processes its stdout asynchronously. The problem is that the async operation takes some time and I want method responsible for process execution to end after all async IO operations are done.

I have code like this:

using System.Diagnostics;

Process process = new Process();
// ...
process.OutputDataReceived += new DataReceivedEventHandler(this.OnRecvStdOut);
process.ErrorDataReceived += new DataReceivedEventHandler(this.OnRecvStdErr);
// ...
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
// ...
process.WaitForExit();

Now I'm looking for a way how to tell the program to wait until all IO (OnRecvStdOut) operations are done.

I though about using one of System.Threading classes, but I'm not sure which class is the best for this and how to do this after all, the best way would probably be:

public void OnRecvStdOut(...)
{
    something.Increase();
    // the stuff that takes so long
    something.DecreaseAndSignal();
}

And in main function:

something.WaitUntilZero();

Note: I'd like to allow both StdErr and StdOut to be processed in parallel. Something can't rely that Wait will be called as much as Signal, because Increase() and DecreaseAndSignal() pairs will be called many times before Wait occurs.

The second thing that came to mind was something that would be able to signal many times (without requirement to process signals) and use loop in main function like:

while( ioOperations > 0){
    something.WaitForSignal(500);
}

Edit: Current working solution:

I came up with this what seems to be working:

using System.Threading;

protected int IOCount = 0;
protected AutoResetEvent _IOSyncEvent = new AutoResetEvent(false);

public void OnRecvStdOut(...)
{
    Interlocked.Increase( ref IOCount);
    // the stuff that takes so long
    Interlocked.Decrease( ref IOCount);
    IOSyncEvent.Set();
}

// After process.WaitForExit()
while( IOCount > 0){
    // 250 for a case that signal occurs after condition and before wait
    IOSyncEvent.WaitOne(250); 
}

But I'd appreciate any notes how to do this "good practice way" or what are possible risks of implementation I though of.

Vyktor
  • 20,559
  • 6
  • 64
  • 96
  • Seems pretty similar to http://stackoverflow.com/questions/2337166/problem-with-standardoutput-stream-in-async-mode. Does that question's answers help? – doug65536 Dec 18 '12 at 02:40
  • Actually, scratch that comment. It suggest hacking into an internal class using reflection (basically, uses undocumented technique). – doug65536 Dec 18 '12 at 02:52

1 Answers1

1

Use a CountdownEvent set to 2. Each data received callback, check the x.EndOfStream flag (where x is standardoutput or standarderror on the process object). If EOF, then signal the countdownevent. It will work because both the standard and error output streams will eventually signal the event. Once both signal it, the wait on it will return. It is also a very efficient way to do it.

doug65536
  • 6,562
  • 3
  • 43
  • 53