process.WaitForExit()异步

时间:2009-01-22 18:13:58

标签: c# .net winforms user-interface asynchronous

我想等待一个进程完成,但是process.WaitForExit()挂起了我的GUI。是否存在基于事件的方式,或者我是否需要在退出之前生成要阻塞的线程,然后自己委派事件?

9 个答案:

答案 0 :(得分:78)

从.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...
}

答案 1 :(得分:27)

process.EnableRaisingEvents = true;
process.Exited + = [EventHandler]

答案 2 :(得分:9)

这是一种稍微清晰的扩展方法,因为它可以清除取消令牌注册和退出事件。它还处理竞争条件边缘情况,其中进程可以在它开始之后但在连接Exited事件之前结束。它使用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;
        }
    }
}

答案 3 :(得分:8)

如果您选择@MgSam答案,请注意,如果您通过WaitForExitAsync某些CancellationToken,将在指定的延迟后自动取消,您可以获得InvalidOperationException。要解决此问题,您需要更改

cancellationToken.Register(tcs.SetCanceled);

cancellationToken.Register( () => { tcs.TrySetCanceled(); } );

P.S。:不要忘记及时处理你的CancellationTokenSource

答案 4 :(得分:4)

According to this link WaitForExit()方法用于使当前线程等待,直到关联的进程终止。但是,进程确实有一个可以挂钩的退出事件。

答案 5 :(得分:1)

使用System.Diagnostics.Process.Exited

答案 6 :(得分:1)

快速简单的解决方案:

async Task RunProcessWait(string Path)
{
    Process MyProcess = Process.Start(Path);
    while (!MyProcess.HasExited)
        await Task.Delay(100);
}

await RunProcessWait("C:\...")

答案 7 :(得分:0)

Ryan解决方案在Windows上效果很好。在OSX上发生了奇怪的事情,可能是tcs.TrySetResult()的死锁!有两种解决方案:

第一个:

tcs.TrySetResult()包装到Task.Run():

    public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
    {
        var tcs = new TaskCompletionSource<bool>();

        void Process_Exited(object sender, EventArgs e)
        {
            Task.Run(() => tcs.TrySetResult(true));
        }

        process.EnableRaisingEvents = true;
        process.Exited += Process_Exited;

        try
        {
            if (process.HasExited)
            {
                return;
            }

            using (cancellationToken.Register(() => Task.Run(() => tcs.TrySetCanceled())))
            {
                await tcs.Task;
            }
        }
        finally
        {
            process.Exited -= Process_Exited;
        }
    }

有关此问题的对话以及更多详细信息: Calling TaskCompletionSource.SetResult in a non blocking manner

第二个:

    public static async Task WaitForExitAsync(this Process process, CancellationToken cancellationToken)
    {
        while (!process.HasExited)
        {
            await Task.Delay(100, cancellationToken);
        }
    }

您可以将轮询间隔从100毫秒增加到更多,具体取决于您的应用。

答案 8 :(得分:0)

.NET5 开始,WaitForExitAsync class 现在提供了 Process

await process.WaitForExitAsync( token );