LINUX.ORG.RU

Popen PIPE пишет много раз

 , ,


1

3

Нужно чтоб питон-скритп запустил программу и через некоторое время написал строчку в программу.

Если просто представить, то есть CPP программа:

#include <iostream>
#include <fstream>

using namespace std;
int main()
{
   std::string input;
   int i = 0;
   ofstream myfile("/var/tmp/result.txt", ios::out);
   while (1)
   {
      std::cin >> input;
      std::cout << "get: " << input << "; i = " << i << std::endl;
      myfile << "get: " << input << "; i = " << i << std::endl;
      i++;
      if (i > 10 )
         return 0;
   }
}
И питон скрипт:
#!/usr/bin/python
from subprocess import Popen, PIPE
import time

CMD="/home/y/test/build-console-Desktop/./myApp"
handle = Popen(CMD, shell=True, stdin=PIPE) 

time.sleep(2)
print "write now"
handle.stdin.write("123")
handle.stdin.flush()
handle.stdin.close()
time.sleep(2)

Я ожидаю, что программа один раз зайдет в цикл и будет ждать пока не будет повторно что-то записано.
Но на практике я получаю вывод:
$ ./test_py/test_small.py
write now # - это пишет питон
get: 123; i = 0 # это и до конца CPP
get: 123; i = 1
get: 123; i = 2
get: 123; i = 3
get: 123; i = 4
get: 123; i = 5
get: 123; i = 6
get: 123; i = 7
get: 123; i = 8
get: 123; i = 9
get: 123; i = 10

Вопрос: как сделать чтоб CPP программа читала только 1 раз? Очень желательно без изменения CPP кода.

★★★★

Последнее исправление: ymuv (всего исправлений: 2)
Ответ на: комментарий от Reedych

Код CPP это пример.

я не знаю что такое man

Ты про это?
man popen

Since the standard input of a command opened for reading shares its seek offset with the process that called popen(), if the original process has done a buffered read, the command's input position may not be as expected. Similarly, the output from a command opened for writing may become intermingled with that of the original process. The latter can be avoided by calling fflush(3) before popen().

Сделал:

handle = Popen(CMD, shell=True, stdin=PIPE) 
time.sleep(2)
handle.stdin.flush()
handle.stdin.write("123")
time.sleep(2)
Результат тот-же.

ymuv ★★★★
() автор топика
Последнее исправление: ymuv (всего исправлений: 1)
Ответ на: [:||||:] от mos

У вас в Екатеринбург только 18:30. Когда вы уже успели отпраздновать?

ymuv ★★★★
() автор топика

Я ожидаю, что программа один раз зайдет в цикл и будет ждать пока не будет повторно что-то записано.

Она и ждет, ровно до того момента как ей закрывают stdin

anonymous
()

#! usr/bin/env python

import subprocess
import select
from subprocess import Popen


def main():
    proc = Popen(['./a.out'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

    while proc.poll() is None:
        while True:
            if select.select([], [proc.stdin], [], 1.0)[1]:
                proc.stdin.write(b'123\n')
                proc.stdin.flush()
                print('written')
                break

        while True:
            if select.select([proc.stdout], [], [], 1.0)[0]:
                print('reading')
                line = proc.stdout.readline()
                print(line)
                break


if __name__ == '__main__':
    main()

anonymous
()
Ответ на: комментарий от anonymous

Не, мне не нравится. Ты всерьёз считаешь, что для того, чтобы писать в stdin дочернего процесса надо во так вот изголяться?

anonymous
()
Ответ на: комментарий от anonymous

Ну не изголяйся, все стандартные IO операции и методы доступные в subprocess блокируют. Так что или ты используешь select или не можешь писать и читать одновременно. Конкретный вид кода зависит от потребностей, но select нормальный вариант non-blocking IO стандартными средствами.

anonymous
()
Ответ на: комментарий от anonymous

select

Ничего не имею против select, но он явно не нужен, если мы просто хотим записать что-то в stdin. В скрипте постера, по крайней мере, я не вижу другой полезной функции.

anonymous
()
#!/usr/bin/python
from subprocess import Popen, PIPE
import time

CMD="/home/y/test/build-console-Desktop/myApp"
handle = Popen(CMD, stdin=PIPE) 

handle.stdin.write("123\n")
handle.stdin.flush()
time.sleep(2)
anonymous
()
Ответ на: комментарий от anonymous

stdin.write может заблокировать если процесс не читает и буфер переполняется, со стандартными потоками можно долго наступать на грабли в некоторых специфичных случаях. Вариант с select универсальный, будет работать всегда.

А так да, если нужно записать одну строку и забыть, то не обязательно изголяться, можно просто использовать POopen.communicate.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.