процесс.WaitForExit() асинхронно
Я хочу дождаться завершения процесса, но process.WaitForExit()
зависает мой GUI. Есть ли способ на основе событий или мне нужно создать поток для блокировки до выхода, а затем делегировать событие самому?
6 ответов
начиная с .NET 4.0 / C# 5, лучше представить это с помощью асинхронного шаблона.
/// <summary>
/// Waits asynchronously for the process to exit.
/// </summary>
/// <param name="process">The process to wait for cancellation.</param>
/// <param name="cancellationToken">A cancellation token. If invoked, the task will return
/// immediately as canceled.</param>
/// <returns>A Task representing waiting for the process to end.</returns>
public static Task WaitForExitAsync(this Process process,
CancellationToken cancellationToken = default(CancellationToken))
{
var tcs = new TaskCompletionSource<object>();
process.EnableRaisingEvents = true;
process.Exited += (sender, args) => tcs.TrySetResult(null);
if(cancellationToken != default(CancellationToken))
cancellationToken.Register(tcs.SetCanceled);
return tcs.Task;
}
использование:
public async void Test()
{
var process = new Process("processName");
process.Start();
await process.WaitForExitAsync();
//Do some fun stuff here...
}
если вы выбираете @MgSam ответ, имейте в виду, если вы проходите через WaitForExitAsync
некоторые CancellationToken
, который будет автоматически отменен после указанной задержки, вы можете получить InvalidOperationException
. Чтобы исправить это, вам нужно изменить
cancellationToken.Register(tcs.SetCanceled);
to
cancellationToken.Register( () => { tcs.TrySetCanceled(); } );
P. S.: Не забудьте выбросить CancellationTokenSource
в время.
вот метод расширения, который немного чище, потому что он очищает регистрацию токена отмены и выходное событие. Он также обрабатывает крайний случай состояния гонки, где процесс может закончиться после его запуска, но до того, как выходное событие было присоединено. Он использует новый синтаксис локальных функций в C# 7.
public static class ProcessExtensions
{
public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
{
var tcs = new TaskCompletionSource<bool>();
void Process_Exited(object sender, EventArgs e)
{
tcs.TrySetResult(true);
}
process.EnableRaisingEvents = true;
process.Exited += Process_Exited;
try
{
if (process.HasExited)
{
return;
}
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
{
await tcs.Task;
}
}
finally
{
process.Exited -= Process_Exited;
}
}
}
по этой ссылке метод WaitForExit () используется для того, чтобы заставить текущий поток ждать завершения связанного процесса. Однако у процесса есть выходное событие, которое вы можете подключить.