Python Popen записывает и читает процесс io несколько раз

Вопрос касается Python инструмент. У меня есть приложение с графическим интерфейсом, которое использует Tkinter, но я думаю, что конкретная библиотека с графическим интерфейсом не так важна для вопроса. Хотя я могу добавить дополнительные правки позже по запросу.

Цель моего приложения — компилировать и запускать некоторые программы. Отображается вывод программы, и пользователь также может писать на ввод программы. Вопрос звучит следующим образом:

Как общаться с Popen, чтобы он ждал записи на свой стандартный ввод и чтения своего стандартного вывода несколько раз?

В моем приложении с графическим интерфейсом у меня есть следующие элементы пользовательского интерфейса:

  1. Кнопка «Выполнить», которая запускает скомпилированный двоичный файл. оно использует Popen
  2. Поле ввода текста, которое я хочу использовать для предоставления к запущенному процессу
  3. Текстовое поле только для чтения, которое отображает вывод программы. Я хотел бы обновлять его по мере продвижения программы.

Многие программы, которые только печатают данные, работают нормально. Например программа Hello World работает как положено. Но когда программа содержит чтение пользовательского ввода, у меня возникают проблемы.

Вот псевдокод целевой программы:

      int x = 1 ;
println "enter an integer to echo";
read x ; 
println x 

Вызывает функцию C под капотом.

Если это поможет, существует версия программного кода, более специфичная для реализации. Это может или не может быть полезно для понимания вопроса. Пожалуйста, смотрите ARM-сборку внизу, если хотите.

Я компилирую исходный код в сборку ARM, а затем превращаю его в двоичный исполняемый файл. я использую для запуска скомпилированного двоичного файла.

Вот как я называю это программно в Python:

      import subprocess
import threading


def emulate(app, executable):
    app.proc = subprocess.Popen(
        ["qemu-arm", "-L", "/usr/arm-linux-gnueabi/", executable],
        stdout=subprocess.PIPE,
        stdin=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    stdout_output, _ = woutput.proc.communicate()

    app.write(stdout_output)


class App:

    # self.entry = edit text entry object
    # self.text = read only text field object
    # self.proc = initialized with None, but assigned to Popen later

    # ... something not important

    def run(self, compile_command, target_dir, file_name):

        # ... something not important

        binary_executable = "/path/to/out"
        trd = threading.Thread(target=emulate, args=(self, binary_executable))
        trd.start()

    def write(self, text):
        # Writing to tkinter Text field
        self.text.insert('end', text)

    def _pass_entry_to_stdin_of_proccess(self, event):
        ''' Magic function, which is binded to user pressing Enter after
            typing text to the text entry '''

        self.proc.stdin.write(self.entry.get().encode('utf-8'))
        self.entry.delete(0, END)
        self.write(self.proc.stdout.read().decode('utf-8'))

Как вы могли заметить, я запускаю Popen в отдельном потоке. Это добавляет сложности, и, возможно, более разумное решение позволит избежать этого. Я могу не знать некоторых особенностей а также . Я все еще учусь.

В любом случае, идея состоит в том, чтобы позвонить когда пользователь нажимает Enter после записи текста в текстовое поле. Чтобы это произошло правильно, процесс Popen должен ожидать ввода ввода-вывода. Проблема с заключается в том, что его нельзя вызывать несколько раз. Он ждет окончания процесса. Но процесс называется ак , что требует ожидания. В голове у меня противоречие, но вот что происходит на самом деле:

  1. Окончательное значение stdout равно b'enter an integer to echo\n0\n'

  2. Получается сразу после нажатия кнопки "Выполнить". Это означает, что процесс Popen не ждет . Вместо этого он как-то читается не дожидаясь ио.

  3. Затем этот ноль записывается в с предыдущим сообщением.

  4. Призыв заканчивается, и данные передаются в текст.

Резюме: Как организовать переключение между main и Popen процессами с правильным ожиданием?####

Файл сборки out.s, о котором упоминалось ранее:
          .data

    msg_0:
        .word 5
        .ascii    "%.*s\0"
            return
    msg_1:
        .word 24
        .ascii    "enter an integer to echo"
    msg_2:
        .word 1
        .ascii    "\0"
    msg_3:
        .word 3
        .ascii    "%d\0"
    .text
    
    .global main
    main:
        PUSH {lr}
        SUB sp, sp, #4
        LDR r0, =1 
        STR r0, [sp]
        LDR r4, =msg_1 
        MOV r0, r4
        BL p_print_string
        BL p_print_ln
        PUSH {r0}
        MOV r0, sp
        BL p_read_int
        POP {r0}
        STR r0, [sp]
        MOV r4, r0
        ADD r0, r4, #0
        BL p_print_int
        BL p_print_ln
        LDR r0, =0 
        ADD sp, sp, #4
        MOV r0, r0
        POP {pc}
        .ltorg
    p_print_string:
        PUSH {lr}
        LDR r1, [r0] 
        ADD r2, r0, #4
        LDR r0, =msg_0 
        ADD r0, r0, #4
        BL printf
        MOV r0, #0
        BL fflush
        POP {pc}
    p_print_ln:
        PUSH {lr}
        LDR r0, =msg_2 
        ADD r0, r0, #4
        BL puts
        MOV r0, #0
        BL fflush
        POP {pc}
    p_read_int:
        PUSH {lr}
        MOV r1, r0
        LDR r0, =msg_3 
        ADD r0, r0, #4
        BL scanf
        POP {pc}
    p_print_int:
        PUSH {lr}
        MOV r1, r0
        LDR r0, =msg_3 
        ADD r0, r0, #4
        BL printf
        MOV r0, #0
        BL fflush
        POP {pc}

0 ответов

Другие вопросы по тегам