python – fork e comunicazione tra processi

Nel seguente programma, utilizzando il calcolo della serie di fibonacci per pretesto, mostro un esempio di utilizzo del fork e della comunicazione tra processi.

Ai fini del calcolo dei termini della successione di fibonacci utilizzo una funzione ricorsiva che richiama se stessa fino a che non arriva a termini noti: non è il massimo per quel che riguarda le prestazioni ma è comoda e compatta e in questo caso è solo un pretesto.

Iniziamo dal listato del programma:

#!/usr/bin/env python3 
import os, sys

def fib_rec(n):
    """calculate Fibonacci series up to n"""
    if n == 1:
       return 1
    elif n == 2:
       return 1
    else:
       return fib_rec(n-1)+fib_rec(n-2)

while 1:
    r,w=os.pipe()

    num = int(input("Please enter an integer: "))

    pid = os.fork()
    if pid:          # Parent
        while 1:
            data=os.read(r,64)
            if data == (" ").encode():
                break
            else:
                print (str(pid)+": child calculate: " + str(data))
    else:           # Child
        count=1;
        while count <= num:
            fibn =  fib_rec(count)
            # il loop serve a passare parole di 64 byte fisse visto che poi leggo byte per byte
            count2 = 1
            while count2 <= 64 - len(str(fibn)):
                os.write(w, ("").encode());
                count2 = count2 + 1
            msg = (str(fibn)).encode()
            os.write(w, msg)
            count = count+1
        # invio stringa vuota per chiudere pipe
        count2 = 1
        while count2 < 64 :
            os.write(w, ("").encode());
            count2 = count2 + 1
        os.write(w, (" ").encode());
        exit(0)

Non spieghiamo nel dettaglio fib_rec che è semplicemente una funzione ricorsiva per il calcolo della successione di fibonacci.

Il programma è costituito da un loop infinito nel quale viene chiesto quanto deve essere lunga la successione da calcolare. Ad ogni ciclo il programma definisce una pipe, genera un processo child per eseguire il calcolo e mostra a video i risultati calcolati dal processo figlio e passati al processo padre.

Vediamo più nel dettaglio:

    r,w=os.pipe()

definisce la pipe e restituisce due file descriptor; il primo è utilizzabile per leggere ed il secondo per scrivere.

Una volta ottenuta la lunghezza della sequenza da calcolare, il programma genera il figlio

pid = os.fork()

l'esecuzione del programma procede da qui sia per il processo padre sia per quello figlio ma nel caso del padre pid conterrà il pid del figlio, nel caso del figlio pid conterrà il valore 0. Questo viene usato per distinguere il comportamento di padre e figlio.

Il processo padre entra in un loop infinito in cui legge parole di 64 byte dalla pipe e da cui esce se il valore ritornato è uno spazio.

    if pid:          # Parent
        while 1:
            data=os.read(r,64)
            if data == (" ").encode():
                break
            else:
                print (str(pid)+": child calculate: " + str(data))

Il processo figlio, di contro, calcola i termini della successione di fibonacci e li scrive nella pipe assieme a tanti caratteri vuoti quanti ne servono per completare la parola di 64 byte. Terminata la sequenza, invia una stringa contenente un solo spazio per dire al processo padre di concludere il suo ciclo ed esce.

        count=1;
        while count <= num:
            fibn =  fib_rec(count)
            # il loop serve a passare parole di 64 byte fisse visto che poi leggo byte per byte
            count2 = 1
            while count2 <= 64 - len(str(fibn)):
                os.write(w, ("").encode());
                count2 = count2 + 1
            msg = (str(fibn)).encode()
            os.write(w, msg)
            count = count+1
        # invio stringa vuota per chiudere pipe
        count2 = 1
        while count2 < 64 :
            os.write(w, ("").encode());
            count2 = count2 + 1
        os.write(w, (" ").encode());
        exit(0)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *