Трубные киоски с перенаправлением ввода / вывода
Мы пытаемся добавить в язык программирования ooRexx возможность, позволяющую программисту выдавать команду операционной системы с возможностью перенаправления ввода / вывода в потоках stdin, stdout и stderr. Мы делаем это как для Windows, так и для всех Unix-систем.
У нас есть настройки для обеих сред, и настройки в основном одинаковы:
- создать соответствующие каналы для запрашиваемого перенаправления.
- запустить новый процесс для обработки команды.
- Запишите входные данные в канал stdin.
- Чтение с канала stdout, затем чтение с канала stderr.
У нас возникают проблемы с остановкой, когда во входной канал записывается большое количество данных, а также большое количество выходных данных. Если во время записи в stdin и канал заполнен, мы заблокированы. Однако, если запущенному процессу также удается заполнить выходной канал, он также блокируется. В результате весь трубопровод глохнет и все зависает. Наш код застревает при попытке записи во входной канал, пока из него не будут считаны некоторые данные. Процесс застревает при попытке записи в выходной канал до тех пор, пока не будут прочитаны некоторые данные, чего не произойдет, потому что запись на вход остановлена. Классические смертельные объятия.
Я исследовал множество различных вариантов неблокирующего ввода-вывода как в Windows, так и в Linux, но до сих пор не нашел ничего, что не вызывало бы других проблем, таких как потеря данных. Кто-нибудь есть какие-либо предложения о том, как это можно сделать?
Для интересующихся, вот ссылка на код, который обрабатывает конец Windows этого:
и вот версия для Linux
1 ответ
Похоже, что Python документирует похожий тип тупика в своей документации. Похоже , исходный код Python (см. Вокруг строки 900 и _communicate
) обрабатывает это, создавая несколько потоков демонов чтения, которые читают из выходного канала во время записи во входной канал, когда communicate
метод называется.
Хотя этот тип конструкции сделан для языка более высокого уровня (Python), я думаю, что было бы неплохо создать потоки, которые будут читать каналы вывода, в то же время записывая в канал ввода в основной программе. Хотя я на самом деле не использовал потоки в C++/C, поэтому я не могу поручиться за его эффективность или возможные подводные камни при использовании потоков.
Проблема, с которой я мог бы столкнуться при использовании нескольких потоков (как всегда), заключается в том, что вам необходимо убедиться, что вы учли все возможные гонки данных, указав соответствующий код синхронизации.