Reputation: 149
Let's imagine we have such code:
public class MyProcess
{
private Process _process;
public event EventHandler OnFinish;
public MyProcess(string pathToExe)
{
_process = new Process();
_process.StartInfo.FileName = pathToExe;
}
public int Start()
{
_process.Exited += _processExited;
_process.Start();
return _process.Id;
}
public void Stop()
{
_process.Stop();
}
private void _processExited(object sender, EventArgs e)
{
OnFinish?.Invoke();
}
}
public class MyProgram
{
private static int stoppedProcs = 0;
public static void Main(string[] args)
{
var proc = new MyProcess("foo.exe");
proc.OnFinish += proc_OnFinish;
proc.Start();
proc.Stop();
//Wait here to display 1 instead of 0
Console.WriteLine(stoppedProcs);
}
private static void proc_OnFinish(object sender, EventArgs e)
{
stoppedProcs++;
}
}
I create and launch process. Then I want to stop it and continue only after I handle the event. The problem is I do not invoke event by myself as it is done by OS. How can I understand that event handlers are finished?
Upvotes: 2
Views: 3371
Reputation: 149
Thanks everyone for answering my question.
The problem was solved easily with @Fildor' s suggestion to use ManualResetEvent
public class MyProgram
{
private static int stoppedProcs = 0;
private static ManualResetEvent mre = new ManualResetEvent(false);
public static void Main(string[] args)
{
var proc = new MyProcess("foo.exe");
proc.OnFinish += proc_OnFinish;
proc.Start();
proc.Stop();
//Wait here to display 1 instead of 0
mre.WaitOne();
mre.Reset();
Console.WriteLine(stoppedProcs);
}
private static void proc_OnFinish(object sender, EventArgs e)
{
stoppedProcs++;
mre.Set();
}
}
Upvotes: 4
Reputation: 10035
To extend answers mentioning Task
and await
stuff
If you want to turn the wait into an async flow, you could combine the Exited
event with a TaskCompletionSource
like this:
public static class ProcessExtension
{
public static Task WaitForExitAsync(this Process proc, Action callback)
{
return new WaitForExitExt(proc, callback).WaitTask;
}
class WaitForExitExt
{
private TaskCompletionSource<int> _tcs;
private Action _callback;
public WaitForExitExt(Process proc, Action callback)
{
_callback = callback;
proc.EnableRaisingEvents = true;
_tcs = new TaskCompletionSource<int>();
if (proc.HasExited)
{
_tcs.TrySetResult(proc.ExitCode);
}
else
{
proc.Exited += OnProcessExited;
// Process already exited by the time the handler was attached.
if (proc.HasExited)
{
proc.Exited -= OnProcessExited;
_tcs.TrySetResult(proc.ExitCode);
}
}
}
public Task WaitTask => _tcs.Task;
private void OnProcessExited(object sender, EventArgs e)
{
var proc = (Process)sender;
proc.Exited -= OnProcessExited;
_callback();
_tcs.TrySetResult(proc.ExitCode);
}
}
}
The above extension enables the ability to run a callback
once the process exited, and the callback
is guaranteed to be run before the task is completed, so you could use it in your code like:
var process = new Process();
process.StartInfo.FileName = "notepad.exe";
process.EnableRaisingEvents = true;
process.Start();
var task = process.WaitForExitAsync(() => Console.WriteLine("Exited"));
process.Kill();
await task;
Console.WriteLine("Task finished");
And the output is:
Exited
Task finished
Upvotes: 0
Reputation: 43384
Assuming that you want to wait synchronously (blocking the current thread), just expose through your class the Process.WaitForExit
method.
public void WaitForExit()
{
_process.WaitForExit();
}
Upvotes: 1