Se você se livrar do material de encerramento e desligamento (o que é inseguro e você pode, em um caso extremo, mas não insondável, quando child.py
morre antes que a subcamada (head -n 1 shutdown; kill -9 $parent) &
acabe kill -9
ing algum processo inocente ),
então child.py
não será encerrado porque seu parent.py
não está se comportando como um bom cidadão do UNIX.
O subprocesso cat std_out &
terá terminado quando você enviar a mensagem quit
, porque o gravador de std_out
é child_original.py
, que termina ao receber quit
, quando fecha seu stdout
, que é o std_out
pipe e que close
fará o subprocesso cat
terminar.
O cat > std_in
não está terminando porque está lendo um pipe originado no processo parent.py
e o processo parent.py
não se preocupou em fechar esse canal. Se assim fosse, cat > stdin_in
e consequentemente todo o child.py
terminaria sozinho e você não precisaria do pipe de desligamento ou da killing
part (matar um processo que não é seu filho no UNIX é sempre um potencial de segurança buraco se uma condição de corrida causada devido à reciclagem rápida do PID ocorrer.)
Processos na extremidade direita de um pipeline geralmente só terminam quando eles terminam de ler seu stdin, mas como você não está fechando isso ( child.stdin
), você está dizendo implicitamente ao processo filho "wait, i have mais entrada para você "e então você vai matá-lo, porque ele espera por mais entrada de você como deveria.
Em suma, faça com que parent.py
se comporte de maneira razoável:
from __future__ import print_function
from subprocess import Popen, PIPE
import os
child = Popen('./child.py', stdin=PIPE, stdout=PIPE)
for letter in 'abcde':
print('Parent writes to child: ', letter)
child.stdin.write(letter+'\n')
child.stdin.flush()
response = child.stdout.readline()
print('Response from the child:', response)
assert response.rstrip() == letter.upper(), 'Wrong response'
child.stdin.write('quit\n')
child.stdin.flush()
child.stdin.close()
print('Waiting for the child to terminate...')
child.wait()
print('Done!')
E o seu child.py
pode ser tão simples quanto
#!/bin/sh
cat std_out &
cat > std_in
wait #basically to assert that cat std_out has finished at this point
(Note que me livrei daquelas chamadas do fd dup porque de outra forma você precisaria fechar o child.stdin
e o child_stdin
duplicado).
Como parent.py
opera de maneira orientada por linhas, gnu cat
é sem buffer (como mikeserv apontou) e child_original.py
opera de maneira orientada a linhas, você efetivamente tem a coisa toda com buffer de linha. / p>
Observação no Cat: O Unbufferred pode não ser o termo mais sortudo, pois o gnu cat
usa um buffer. O que ele não faz é tentar obter todo o buffer antes de escrever as coisas (ao contrário do stdio). Basicamente, ele faz solicitações de leitura ao sistema operacional para um tamanho específico (seu tamanho de buffer) e grava o que recebe sem esperá-lo para obter uma linha inteira ou o buffer inteiro. ( read (2) pode ser preguiçoso e dar a você apenas o que ele pode lhe dar no momento em vez do todo buffer que você pediu.)
(Você pode inspecionar o código-fonte em link ; safe_read
(usado em vez de read
puro) está no submódulo gnulib
e é um wrapper muito simples em torno de read (2 ) que abstrai EINTR
(veja a man page)).