Класс .NET Console
и его реализация по умолчанию TextWriter
(доступная как Console.Out
и неявно, например, Console.WriteLine()
) не сигнализируют о какой-либо ошибке, когда приложение передает свой вывод в другую программу, а другая программа завершает или закрывает трубку до завершения работы приложения. Это означает, что приложение может работать дольше, чем необходимо, записывая вывод в черную дыру.
Как я могу обнаружить закрытие другого конца переадресации?
Ниже приведено более подробное объяснение:
Вот пара примеров программ, которые демонстрируют проблему. Produce
довольно медленно печатает множество целых чисел, чтобы имитировать эффект вычисления:
using System;
class Produce
{
static void Main()
{
for (int i = 0; i < 10000; ++i)
{
System.Threading.Thread.Sleep(100); // added for effect
Console.WriteLine(i);
}
}
}
Consume
только считывает первые 10 строк ввода и затем выходит:
using System;
class Consume
{
static void Main()
{
for (int i = 0; i < 10; ++i)
Console.ReadLine();
}
}
Если эти две программы скомпилированы, а вывод первого - со вторым, так:
Produce | Consume
... можно заметить, что Produce
продолжает работать после завершения Consume
.
В действительности моя программа Consume
- это стиль Unix head
, а моя программа Produce
печатает данные, которые дорого рассчитать. Я хотел бы завершить вывод, когда другой конец канала закрыл соединение.
Как это сделать в .NET?
(Я знаю, что очевидной альтернативой является передача аргумента командной строки для ограничения вывода и действительно того, что я сейчас делаю, но я все равно хотел бы знать, как это сделать, поскольку я хочу быть в состоянии чтобы сделать более настраиваемые суждения о том, когда прекратить чтение, например, проложить через grep
до head
.)
UPDATE:. Это выглядит ужасно, как реализация System.IO.__ConsoleStream
в .NET жестко запрограммирована для игнорирования ошибок 0x6D (ERROR_BROKEN_PIPE
) и 0xE8 (ERROR_NO_DATA
). Вероятно, это означает, что мне нужно повторно реализовать консольный поток. Вздох...)