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);
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With