虽然Process.HasExited是真的Process.WaitForExit不回连 [英] Process.WaitForExit doesn't return even though Process.HasExited is true

查看:850
本文介绍了虽然Process.HasExited是真的Process.WaitForExit不回连的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用的Process.Start启动一个批处理文件。该批处理文件使用开始命令启动并行几个程序,然后退出。

I use Process.Start to start a batch file. The batch file uses the "START" command to start several programs in parallel and then exits.

在该批处理文件完成Process.HasExited变得真实,Process.Exit code包含正确的退出code。

Once the batch file is done Process.HasExited becomes true and Process.ExitCode contains the correct exit code.

但是,当我打电话Process.WaitForExit()挂起/永不再来。

But when I call Process.WaitForExit() it hangs / never returns.

下面这段code演示了此问题。它创建一个批处理文件,启动它,然后打印:

The following piece of code demonstrates the problem. It creates a batch file, starts it and then prints:

Process is still running...
Batch file is done!
Process has exited. Exit code: 123
Calling WaitForExit()...

然后应该打印:

It should then print:

WaitForExit returned.

...但它从来不会(即使HasExited是真实的,我们已经有一个退出code)。

... but it never does (even though HasExited is true and we already have an ExitCode).

open System.IO
open System.Diagnostics
open System.Threading

let foobat = """
  START ping -t localhost
  START ping -t google.com
  ECHO Batch file is done!
  EXIT /B 123
"""

File.WriteAllText("foo.bat", foobat)

use p = new Process(StartInfo = ProcessStartInfo("foo.bat",
                                                 UseShellExecute = false,
                                                 RedirectStandardOutput = true,
                                                 RedirectStandardError = true))

let onOutput = DataReceivedEventHandler(fun _ args -> printfn "%s" args.Data)

p.OutputDataReceived.AddHandler onOutput
p.ErrorDataReceived.AddHandler onOutput

p.Start() |> ignore

p.BeginErrorReadLine()
p.BeginOutputReadLine()

while not p.HasExited do
  printfn "Process is still running..."
  Thread.Sleep(1000)

printfn "Process has exited. Exit code: %d" p.ExitCode

printfn "Calling WaitForExit()..."
p.WaitForExit()|> ignore
printfn "WaitForExit returned."

我注意到,这只是发生在批处理文件包含开始命令,并在标准输出和/或标准错误重定向。

I noticed that this only happens when the batch file contains "START" commands and when standard output and/or standard error are redirected.

为什么WaitForExit()永远不会返回?

Why does WaitForExit() never return?

什么是正确的方式来等待这样一个进程退出?

What's the right way to wait for such a process to exit?

它是安全的只是查询Process.HasExited还是可以的结果在其他问题?

Is it safe to just poll Process.HasExited or can that result in other problems?

PS:我只注意到调用WaitForExit( 100000 )与巨大超时(即绝对不会过期)立即返回进程退出的时候。奇怪的。如果没有超时死了。

PS.: I just noticed that calling WaitForExit(100000) with a huge timeout (that definitely doesn't expire) returns immediately when the process exits. Wierd. Without timeout it hangs.

推荐答案

这似乎是一个假象(我会说错误)在StandardOutput和StandardError的的基于事件的异步处理的具体实施。

This seems to be an artifact (I'd say "bug") in the specific implementation of the event-based asynchronous handling of StandardOutput and StandardError.

我发现,虽然我能轻松地再现您的问题,只需通过运行时提供的code(优秀code为例,顺便说一句!:)),这个过程实际上并没有无限期挂起。相反,它从WaitForExit()返回一旦双方即已经开始了自己退出的子进程。

I noticed that while I was able to easily reproduce your problem, simply by running the code you provided (excellent code example, by the way! :) ), the process did not actually hang indefinitely. Rather, it returned from WaitForExit() once both of the child processes that had been started had themselves exited.

为什么这是应该的,我不能说。我的意思是,这是很清楚的,不知怎的,进程类连接输出和错误的其处理的子进程以及行为。但为什么?而且,由于阅读StandardOutput和StandardError的直接工作正常,这似乎是在基于事件的API的实现中的错误,使用BeginOutputReadLine()和BeginErrorReadLine()。

Why that should be, I can't say. I mean, it's clear enough from the behavior that somehow the Process class is connecting its handling of stdout and stderr to the child processes as well. But why? And since reading StandardOutput and StandardError directly works fine, it appears to be a bug in the implementation of the event-based API, using BeginOutputReadLine() and BeginErrorReadLine().

也就是说,当我改变了程序,以便它,而不是使用StandardOutput和StandardError的直接,它工作正常。例如(C#,因为我不知道F#足够好,拍这样的code例如在一起快:)):

That is, when I changed the program so that it instead used StandardOutput and StandardError directly, it works fine. For example (C#, because I don't know F# well enough to slap a code example like this together quickly :) ):

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

namespace TestSO26713374WaitForExit
{
    class Program
    {
        static void Main(string[] args)
        {
            string foobat =
@"START ping -t localhost
START ping -t google.com
ECHO Batch file is done!
EXIT /B 123
";

            File.WriteAllText("foo.bat", foobat);

            Process p = new Process { StartInfo =
                new ProcessStartInfo("foo.bat")
                {
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                } };

            p.Start();

            var _ = ConsumeReader(p.StandardOutput);
            _ = ConsumeReader(p.StandardError);

            Console.WriteLine("Calling WaitForExit()...");
            p.WaitForExit();
            Console.WriteLine("Process has exited. Exit code: {0}", p.ExitCode);
            Console.WriteLine("WaitForExit returned.");
        }

        async static Task ConsumeReader(TextReader reader)
        {
            string text;

            while ((text = await reader.ReadLineAsync()) != null)
            {
                Console.WriteLine(text);
            }
        }
    }
}

因此​​,虽然我没有整体问题的一个很好的解释,我有我的什么事情的怀疑。更重要的是,希望上述的变通或类似将解决你遇到的基本问题的东西。

So while I don't have a great explanation of the overall problem, I have my suspicions of what's going on. More important, hopefully the above work-around or something similar will address the basic issue you've run into.

这篇关于虽然Process.HasExited是真的Process.WaitForExit不回连的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆