在使用.NET中的进程时,我已经习惯了退出进程将结束StandardOutput和StandardError的输出的行为。但是,我找到了一个似乎不是这样的exe,并且我想知道我的假设是否错误以及为什么错误。
以下是重现我所看到的问题的代码。它使用特定版本的Android Debug Bridge可执行文件(可从https://hostr.co/bBxxj7gFfMlW获得)。
// before running, terminate any adb.exe processes on the system
// adb.exe's initial run leaves behind a background daemon that changes the
// behavior of future adb.exe runs
var process = new Process
{
StartInfo =
{
FileName = @"C:\Users\[my user]\Downloads\ADB-1.0.31.zip\adb.exe",
Arguments = "connect 127.0.0.1",
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardInput = false,
RedirectStandardOutput = true,
UseShellExecute = false,
}
};
process.Start();
var tasks = new Task[]
{
Task.Run(() => { process.WaitForExit(); Console.WriteLine("Process exited"); }),
Task.Run(() =>
{
int b;
while ((b = process.StandardOutput.BaseStream.ReadByte()) != -1)
{
Console.WriteLine($"STDOUT: {b} ({(char)b})");
}
Console.WriteLine("STDOUT: DONE");
}),
Task.Run(() =>
{
int b;
while ((b = process.StandardError.BaseStream.ReadByte()) != -1)
{
Console.WriteLine($"STDERR: {b} ({(char)b})");
}
Console.WriteLine("STDERR: DONE");
})
};
Task.WaitAll(tasks);
我希望看到该进程运行一段时间,产生一些输出(逐字节地记录到控制台),然后退出。一旦进程退出,从流中读取的任务应该返回-1并退出。
所有这一切都发生了,除了在进程退出后,流保持打开状态,读者任务无限期地挂起在ReadByte()上。
修改
进一步挖掘并在Process的实现中发现了一些代码,强调了我希望流程在流程终止时关闭的期望。在WaitForExit()
中,如果使用BeginOutputDataReadLine()
异步传输输出,则等待调用将阻止确保异步输出读取器收到EOF(code)。如果上面的示例被修改为使用:
process.OutputDataReceived += (o, e) => Console.WriteLine(e.Data);
process.BeginOutputReadLine();
而不是具有从StandardOutput读取字节的显式任务,而WaitForExit()任务永远不会返回(尽管轮询process.HasExited
在一段时间后返回false)!