Fer canonada¶
Es vol acabar de dissenyar un programa fer_canonada.py que té tres paràmetres de línia que anomenarem n (enter), etapa (nom d’un programa), i final (nom d’un programa). Construeix un pipeline de n-1 processos d’un programa etapa amb un darrer procés final. En total hi hauran n processos connectats.
Si disposem del programa prova.py següent:
def prova():
enter=input()
print(str(eval(enter+'+1')))
L’efecte de la comanda de línia següent és:
$ echo "0" | ./fer_canonada 10 ./prova ./prova
10
On prova és un fitxer executable que crida el python3 per executar la funció prova() de prova.py, i fer_canonada el mateix per fer_canonada.py.
Gràficament, el que fa fer_canonada.py és fer el següent diagrama de connexions:
Treballarem amb el mòdul mòdul os per accedir al canal estàndard d’entrada i el de sortida que els tractarem com a fitxers oberts. Farem servir els descriptors o gestors de fitxers (sys.*.fileno()) del sistema en comptes dels que habitualment fa servir python. Usarem també les operacions read(), write(), pipe(), fork(), i execlp().
def canonada(nProc,nomp,nompf):
entSTD=sys.stdin.fileno()
sorSTD=sys.stdout.fileno()
sorp,entp=os.pipe()
for i in range(nProc-1):
sorp=creaFilConnectat(sorp, nomp)
sorp=creaFilConnectat(sorp, nompf)
c= os.read(entSTD,1)
while len(c)!=0:
os.write(entp, c)
c= os.read(entSTD,1)
c = os.read(sorp,1)
while len(c)!=0:
os.write(sorSTD,c) # També sys.stdout.write(str(c,'UTF-8'))
c = os.read(sorp,1)
os.write(sorSTD,bytes('\n','UTF-8')) # També sys.stdout.write('\n')
return os.EX_OK
La funció creaFilConnectat() bifurca un nou procés fent les següents connexions:
El primer paràmetre de la funció representa la sortida d’un pipe creat anteriorment i és l’índex a la taula d’E/S del procés. La sortida d’aquest pipe es connecta al canal estàndard d’entrada del nou procés bifurcat
i el canal estàndard de sortida de l’esmentat procés es connecta amb l’entrada d’un nou pipe creat del que la seva sortida quedarà per connectar més endavant.
A més, la funció
Eliminarà les entrades de la taula d’E/S que no s’usaran tant pel procés pare com el fill.
El procés fill serà substituit per l’executable (segon paràmetre)
Retornarà la sortida del nou pipe per següents connexions.
La figura següent il·lustra les connexions que fa:
i part del codi de la creació del fill connectat a un pipe és:
def creaFilConnectat(sorAnt, executable):
sor, ent=os.pipe() # crea un pipe a la banda dreta */
idProces = os.fork()
if idProces != 0: # pare
os.close(ent)
os.close(sorAnt)
else:
# procés
# +-----+ +-----+
# in -->|ant. |-->sorAnt +->| fill|--+
# +-----+ | +-----+ |
# | |
# | +-+-+ |
# sor +--|0|1|<---+ ent
# +-+-+pipe
#>>>>>>> COMPLETEU AQUÍ CODI PER FER LES CONNEXIONS PREVISTES
# procés
# +-----+ +-----+
# in -->|ant. |------------------>| fill|--+ stdout
# +-----+sorAnt stdin +-----+ |
# |
# +-+-+ |
# sor--|0|1|<---+
# +-+-+pipe
os.close(sorAnt) # Donem de baixa les posicions 4a i 5a
# de la taula E/S
os.close(ent)
# encavalcament amb el programa 'executable'
#>>>>>>>> COMPLETEU AQUÍ CODI PER FER QUE AQUEST PROCÉS
#>>>>>>>> SIGUI EL PROGRAMA QUE HA D'EXECUTAR-SE
os.exit(0)
return(sor)
Copieu el fitxer esborrany.py en el fitxer fer_canonada.py, i:
1- Completeu la part que fa possible les connexions del nou procés bifurcat entre dos pipes creats abans.
2- Completeu la part de codi encarregada de substituir el nou procés per la comanda executable.
3- Completeu la resta de codi: programa principal que llegeix els arguments de la línia, fitxer executable fer_canonada que executa la funció principal de fer_canonada.py. Dissenyar l’executable prova que executa la funció prova() de file:prova.py i comprovar l’exemple d’execució donat.