c# - 忽略子进程的标准输出,危险吗?
问题描述
我有一个应用程序,它启动 1-45 个进程(依赖于工作)并通过命名管道与它们通信。我只stderr
对子进程感兴趣,对重定向进程没有兴趣stdout
。
我编写的代码正是这样做的,我重定向stderr
而不是重定向stdout
,一切都按预期工作。当我说我的意思是,我得到了重定向stderr
,我没有看到任何stdout
出现在父进程控制台上,也没有因为没有重定向而出现任何死锁stdout
。
我关心的是,
stdout
子进程的去向在哪里?这些进程倾向于将大量文本转储到stdout
,我担心它们会填充一些内部buffer
内容,这将导致子进程block
在写入stdout
.
在过去,我还重定向stdout
并只是转储(什么都不做)从异步事件提供的数据。但这样做会产生严重的后果。如上所述,我通过named pipes
与子进程进行通信。我注意到的是,当我重定向stdout
它时,它会影响父进程write
操作的性能named pipes
。
当不重定向stdout
写入时间通常< 1ms
但重定向后stdout
时间跳转到> 4s
...
我的问题是,只重定向是否安全
stderr
?
下面是我用来包装Process
. 我还使用该完善的extension
方法await
来完成该过程。我没有发布,但如果您不熟悉它,我可以发布。
public class ChildProcess
{
public async Task StartProcessAsync( string executablePath, CancellationToken token = default )
{
if ( !File.Exists( executablePath ) )
throw new FileNotFoundException( "The specified rip executable path does not exist", executablePath );
using var process = new Process( );
process.StartInfo.FileName = executablePath;
process.StartInfo.UseShellExecute = false;
process.StartInfo.ErrorDialog = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardError = true;
await StartProcess( process, StdErrorOutput, token ).ConfigureAwait( false );
static void StdErrorOutput( object sender, DataReceivedEventArgs args )
{
if ( string.IsNullOrWhiteSpace( args.Data ) ) return;
}
}
private Task StartProcess( Process process,
DataReceivedEventHandler? stderr, CancellationToken token = default )
{
return Task.Run( async ( ) =>
{
try
{
if ( stderr is object )
process.ErrorDataReceived += stderr;
if ( !process.Start( ) )
throw new ApplicationException( $"Failed to start '{process.StartInfo.FileName}'" );
if ( stderr is object )
process.BeginErrorReadLine( );
await process.WaitForExitAsync( token ).ConfigureAwait( false );
}
finally
{
SafeKill( );
if ( stderr is object )
process.ErrorDataReceived -= stderr;
}
void SafeKill( )
{
try
{
if ( !process.HasExited )
{
process.Refresh( );
if ( stderr is object )
process.CancelErrorRead( );
process.Kill( );
}
}
catch ( Exception ex )
{
Console.WriteLine( ex );
}
}
} );
}
}
编辑
在阅读了 Eryk Sun 留下的评论后,我决定深入研究Process
源代码,看看我是否能弄清楚发生了什么。主要是我有兴趣查看STARTUPINFO
仅指定重定向之一时如何填充结构std
streams
。
我删除了一堆我不感兴趣的代码。据我所知,如果我设置RedirectStandardError
并true
指定结构成员设置RedirectStandardOutput
为. 这导致 上的属性为。false
STARTIPINFO
hStdOutput
stdout
StandardOutput
Process
class
null
如果RedirectStandardOutput
设置为true
子进程的输出,则通过pipe
. 然后创建一个StreamReader
实例并将其分配给StandardOutput
。然后StreamReader
从创建的读取pipe
以获取子进程的输出。
因此,如果
HANDLE
设置为stdout
whenRedirectStandardOutput
设置为false
,为什么我在父进程控制台窗口上看不到输出?输出去哪儿了?
System.Diagnostics.Process.StartWithCreateProcess
SafeFileHandle? childInputPipeHandle = null;
SafeFileHandle? parentOutputPipeHandle = null;
if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
{
if (startInfo.RedirectStandardOutput)
{
CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false);
}
else
{
childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false);
}
startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle();
startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES;
}
/* Code starting the process removed */
if (startInfo.RedirectStandardOutput)
{
Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP());
_standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle!, FileAccess.Read, 4096, false), enc, true, 4096);
}
解决方案
推荐阅读
- vue.js - Vue router authentication-guard 无法识别我的 vuex 商店
- angularjs - 从nodejs重定向到角度ui路由
- javascript - 拨动开关在角度 2 中无法正常工作
- php - 如何使用 id 获取数组以从选择行中取消链接图片
- android - 尝试在 React Native 中编译时出错:无法执行 aapt
- reactjs - 更新状态以确定容器是否在视图中
- c# - WPF UI Control Background changing
- python - 打开从 .txt 转换的 .ipynb 文件时出现非 JSON 错误
- java - 以鼠标点击为中心绘制圆的麻烦
- c++ - 为多个会话保留 XPtr