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:

../../../../_images/canonada.svg

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:

../../../../_images/pipes.svg

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.