Я пытался написать приложение, которое запускает подпроцессы и (среди прочего) отображает их вывод в графическом интерфейсе и позволяет пользователю нажать кнопку, чтобы отменить их. Я запускаю процессы так:
queue = Queue.Queue(500)
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
iothread = threading.Thread(
target=simple_io_thread,
args=(process.stdout, queue))
iothread.daemon=True
iothread.start()
где simple_io_thread определяется следующим образом:
def simple_io_thread(pipe, queue):
while True:
line = pipe.readline()
queue.put(line, block=True)
if line=="":
break
Это работает достаточно хорошо. В моем пользовательском интерфейсе я периодически делаю неблокирующие «get» из очереди. Однако мои проблемы возникают, когда я хочу завершить подпроцесс. (Подпроцесс - это произвольный процесс, а не то, что я написал сам.) Я могу использовать метод terminate для завершения процесса, но я не знаю, как гарантировать, что мой поток ввода-вывода завершится. Обычно он выполняет блокировку ввода / вывода на канале. Это может закончиться или не закончиться через некоторое время после того, как я закончу процесс. (Если подпроцесс породил другой подпроцесс , я могу убить первый подпроцесс, но второй все равно будет держать канал открытым. Я даже не уверен, как заставить таких внуков завершаться чисто. ) После этого поток ввода-вывода попытается поставить в очередь выходные данные, но я не хочу фиксировать чтение из очереди бесконечно.
В идеале я хотел бы, чтобы какой-нибудь способ запросил завершение подпроцесса, блокировку на короткое (<0,5 с) промежуток времени и после этого гарантировалось, что поток ввода-вывода завершился (или завершится своевременно без мешая чему-либо еще) и что я могу прекратить чтение из очереди. </p>
Для меня не критично, что решение использует поток ввода-вывода. Если есть другой способ сделать это, который работает в Windows и Linux с Python 2.6 и графическим интерфейсом Tkinter, это будет хорошо.
РЕДАКТИРОВАТЬ - ответ Уилла и другие вещи, которые я видел в Интернете о том, как сделать это на других языках, предполагают, что операционная система ожидает, что вы просто закроете дескриптор файла в главном потоке, а затем должен выйти поток ввода-вывода о его блокировке читайте. Однако, как я описал в комментарии, это, похоже, не работает для меня. Если я делаю это в главном потоке:
process.stdout.close()
Я получаю:
IOError: close() called during concurrent operation on the same file object.
... в основном потоке. Если я делаю это в главном потоке:
os.close(process.stdout.fileno())
Я получаю:
close failed in file object destructor: IOError: [Errno 9] Bad file descriptor
... позже в основном потоке, когда он пытается закрыть дескриптор файла.