Я запускаю процесс из С# следующим образом:
public bool Execute()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = "the command";
startInfo.FileName = "C:\\MyApp.exe";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
Log.LogMessage("{0} {1}", startInfo.FileName, startInfo.Arguments);
using (Process myProcess = Process.Start(startInfo))
{
StringBuilder output = new StringBuilder();
myProcess.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
Log.LogMessage(Thread.CurrentThread.ManagedThreadId.ToString() + e.Data);
};
myProcess.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e)
{
Log.LogError(Thread.CurrentThread.ManagedThreadId.ToString() + " " + e.Data);
};
myProcess.BeginErrorReadLine();
myProcess.BeginOutputReadLine();
myProcess.WaitForExit();
}
return false;
}
Но это имеет проблему... если приложение, о котором идет речь, пишет std out и std err в этом порядке:
std out: msg 1
std err: msg 2
std out: msg 3
Затем вывод, который я вижу из журналов:
msg 2
msg 1
msg 3
Это похоже на то, что обработчики событий выполняются в другом потоке. Поэтому мой вопрос заключается в том, как сохранить порядок написания процесса в std err и std?
Я думал использовать временную метку, но я не думаю, что это сработает из-за упреждающего характера потоков.
Обновление: подтверждено, что использование метки времени для данных не используется.
Заключительное обновление: принятый ответ решает эту проблему - однако у него есть один недостаток, когда потоки объединены, нет способа узнать, к какому потоку было написано. Следовательно, если вам требуется логика write to stderr == failure, а не код выхода приложения, вы все равно можете быть ввернуты.