.net - 如何避免进程终止通知和标准输出重定向事件之间的竞争条件?

标签 .net stdout race-condition io-redirection

我以一种非常可控的方式将作业排在 ProcessJobManager 中。这将一次最多在 X 个并发进程中处理它们。

启动每个进程后,我将其添加到 List<ActiveProcessJob>并存储一个 WaitHandle对于我的流程 ActiveProcessJobCompleteEvent通过构建 new ManualResetEvent( false ) 的属性并分配其 SafeWaitHandle属性(property)到new SafeWaitHandle( my_process.Handle, false ) .

我通过以下代码等待进程完成(以及任何“new_jobs_queued”):

WaitHandle[] wait_handles =
    active_jobs
    .Select<ActiveProcessJob,WaitHandle>( j => j.CompleteEvent )
    .Union( new WaitHandle[]{ new_jobs_queued} ).ToArray();
WaitHandle.WaitAny( wait_handles );

这会正确检测一个或多个进程(或添加到队列中的项目)的终止;但是,我也在重定向标准输出流并调用 Process.BeginOutputReadLine确保Process.OutputDataReceived事件被触发。

问题是进程终止经常被检测和处理(它在 active_jobs 事件的事件处理程序最后一次触发之前从 Process.OutputDataReceived 列表中删除。在这种情况下,处理程序不能引用进程因为它已经从队列中删除了。

我几乎需要知道进程何时“即将退出”,否则我不知道什么时候可以期待最后一个 OutputDataReceived事件,它显然在与我的 WaitAny 不同的线程上运行等待进程终止的调用。

也许 Process.Exit 保证在最后一个 Process.OutputDataReceived 事件之后和 Process.HasExited 方法返回 true 之前被调用?我需要这样的确定性。

最佳答案

由于重定向的输出流在与处理进程终止信号的线程不同的线程中运行,并且没有其他方式与之同步,因此处理终止信号的线程可能会在处理进程终止信号的线程之前执行其所有工作标准输出事件运行或结束。

Process.Exit 不能保证在所有输出事件完成之前运行,可能是由于疏忽,它在调用 RaiseOnExited 之前不等待流结束,除非您调用 Process.WaitForExit,这是我确定的使用 .NET Reflector 反编译代码。

更新:我实际上在 documentation 中发现了这一点。 ,这似乎建议您必须两次调用 WaitForExit 以确保它完成:

"When standard output has been redirected to asynchronous event handlers, it is possible that output processing will not have completed when this method returns. To ensure that asynchronous event handling has been completed, call the WaitForExit() overload that takes no parameter after receiving a true from this overload."



原来我认为一种解决方法可能是在继续从作业队列中删除对进程的引用之前调用 Process.CancelOutputRead 来删除关联的事件监听器,但这可能不起作用,因为 Process.CancelOutputRead 实际上不执行任何同步清理;它只是设置了一个标志。除了接受输出事件处理程序可能在进程终止处理程序完成并处理错误后运行之外,似乎唯一真正的解决方法是在收到进程终止信号后调用 WaitForExit()。

关于.net - 如何避免进程终止通知和标准输出重定向事件之间的竞争条件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16095292/

相关文章:

c - 对称多处理系统的输出

c - 生产者消费者与消费者陷入僵局

python - 在有 GIL 的情况下,您可以在 Python 中竞争条件吗?

.net - 正在读取自定义 HttpWebResponse StatusDescription?

c# - Windows Phone 8 map 控件 - 如何获取 map 边界

除非遇到换行符,否则 c++ 不会写入控制台

c# - Console.Writeline C# - 记录时丢失 STDOUT

c++ - 从 stdout 读取奇怪的性能问题

.net - 为什么使用 Microsoft AntiXSS 库?

c# - 在 C# 中绘制相对线