我有一个C#应用程序A
,它调用另一个C#应用程序B
,该应用程序调用应用程序C
的多个实例。
我想将应用程序C的输出重定向到应用程序A的输出。
我已经将应用程序B
的输出重新定向到应用程序A
的输出中。
现在,在应用程序B
的代码中,我重定向了每个进程的输出,并且我将重定向的输出打印到控制台。不幸的是,出于某种原因,什么都没有打印出来。
(我目前正在测试它而不使用应用A
- 我只运行应用B
)。
以下是代码:
private void runSingleFile (string execFile, string commandArgs)
{
Process processToRun = new Process();
processToRun .StartInfo.FileName = execFile;
processToRun .StartInfo.Arguments = commandArgs;
processToRun .StartInfo.UseShellExecute = false;
processToRun .StartInfo.RedirectStandardOutput = true;
processToRun .OutputDataReceived += outputRedirection;
processToRun.Start();
Console.WriteLine("");
Thread.Sleep(100);
processToRun.BeginOutputReadLine();
}
private void outputRedirection(object sendingProcess, DataReceivedEventArgs outLine)
{
try
{
if (outLine.Data != null)
Console.WriteLine(outLine.Data);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
}
有什么想法吗?
答案 0 :(得分:1)
您发布的代码有效。给出测试程序
// ConsoleApplication2.exe
static void Main(string[] args)
{
Console.WriteLine("Test1...");
Console.WriteLine("Test2...");
System.Threading.Thread.Sleep(100);
Console.WriteLine("Test3...");
}
称为:
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
Console.ReadLine();
}
产生输出:
显然,在代码的另一部分中没有其他东西工作(你没有向我们展示的东西)。
如果应用程序C
工作正常,最可能的解释是,在B
的所有实例都已完成之前,应用程序C
正在终止。您可能需要添加一些代码,使B
等待C
的所有实例返回。
请注意:
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
//Console.ReadLine(); // ** Don't wait!
}
立即完成,无法返回部分或全部数据(特别是如果您删除了Sleep
中的runSingleFile
来电。
考虑一下:
static long processCount = 0; //ADD
static void runSingleFile(string execFile, string commandArgs)
{
Interlocked.Increment(ref processCount); //ADD
Process processToRun = new Process();
processToRun.StartInfo.FileName = execFile;
processToRun.StartInfo.Arguments = commandArgs;
processToRun.StartInfo.UseShellExecute = false;
processToRun.StartInfo.RedirectStandardOutput = true;
processToRun.OutputDataReceived += outputRedirection;
processToRun.EnableRaisingEvents = true; //ADD
processToRun.Exited += processExited; //ADD
processToRun.Start();
Console.WriteLine("");
processToRun.BeginOutputReadLine();
}
static void processExited(object sender, EventArgs e)
{
Interlocked.Decrement(ref processCount);
}
带
static void Main(string[] args)
{
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
runSingleFile("ConsoleApplication2.exe", "");
while (Interlocked.Read(ref processCount) > 0)
{
System.Threading.Thread.Sleep(100);
}
}
上面的内容使应用程序B
等到所有生成的进程都返回。这个例子很简单,显然可以改进,但我认为它证明了这个问题,并为解决方案提供了一种方法。
你可能想要使用像WaitHandle.WaitAll()
这样更优雅的东西,但是这确实引入了josh注意到输出事件在进程终止之前可能不会触发的问题 - 进程句柄将发出信号表明它已终止但其发布的消息可能仍在队列中。等待Exited
事件整理该竞争条件,因为该事件将始终是队列中的最后一条消息(AFAIK)。
另外,请注意这里使用Interlocked
函数 - Console.WriteLine
是线程安全的,但其他变量访问不是。由于控制台应用程序中没有同步上下文,因此生成的进程引发的事件由线程池中的线程(而不是控制台应用程序的主线程)处理。这介绍了与多线程相关的所有问题,必须妥善管理。
答案 1 :(得分:1)
.net Process
对象无法让人们在正确处理IO方面“做正确的事”。
这些页面列出了一些需要解决的问题:
在您的代码示例中,以下是您需要查看的一些项目:
outputRedirection
回调上收到活动。