Код, который вы опубликовали, работает. Учитывая тестовую программу
// 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()
, но это создает проблему, когда Джош отметил, что ваши выходные события могут не срабатывать до тех пор, пока процесс не завершится - дескриптор процесса будет сигнализировать о его прекращении, но его опубликовано сообщения могут оставаться в очереди. Ожидание на событии Exited
позволяет убрать это условие гонки, поскольку это событие всегда будет последним сообщением в очереди (AFAIK).
Также обратите внимание на использование здесь функций Interlocked
- Console.WriteLine
- это потокобезопасный, но другой доступ к переменной - нет. Поскольку в консольном приложении нет контекста синхронизации, события, вызванные порожденными процессами, обрабатываются потоками в threadpool (а не в основном потоке консольного приложения). Это вводит все проблемы, связанные с многопотоковой обработкой, которые должны управляться надлежащим образом.
Некоторые приложения пишут StandardError вместо StandardOutput, попробовали ли вы перенаправить свой StandardError? –
Я точно знаю, что приложение 'C' пишет в StandardOutput, я его написал ... В любом случае, я пробовал это сейчас - до сих пор ничего. – Idanis