Updated Modifié

1. Le Dîner des Philosophes

1.1. Le Problème

On veut implémenter une solution au Dîner des Philosophes. Pour cela, on va créer des processus enfants qui exécutent la fonction philo(fg,fd) suivante, où les fourchettes gauche (fg) et droite (fd) sont des multiprocessing.Lock.

T = 2
def prendre(f):
    print(f"{pid} {id}: Je vais prendre {f.id}")
    f.acquire() # Bloquant
    print(f"{pid} {id}: J'ai pris {f.id}")

def reposer(f):
    print(f"{pid} {id}: Je repose {f.id}")
    f.release()

def manger():
    print(f"{pid} {id}: Je mange...")
    time.sleep(randrange(T))
    
def philo(fg,fd):
    for r in range(3):
#        time.sleep(randrange(T))
        prendre(fg)
#        time.sleep(randrange(T))
        prendre(fd)
        manger()
	reposer(fg)
    	reposer(fd)
    	print(f"{pid} {id}: J'ai fini !")
    print(f"{pid} {id}: Fini")

Créer un processus parent qui

  • crée NB fourchettes (avec multiprocessing.Lock()), leur affecte un id pour pouvoir les nommer facilement;
  • crée NB processus enfants et leur fait exécuter philo(fg,fd) avec les fourchettes gauche (fg) et droite (fd)
  • attend la fin des NB processus enfants

1.2. Interblocage

Faire plusieurs exécutions du code précédent avec NB=5. Arrive-t-on à éviter l’interblocage ? Que se passe-t-t-il si l’on décommente les deux lignes sleep ? Pourquoi ? Que se passe-t-il si l’on remplace le for r in range(3): par while True: ?

1.3. Solution

Modifier le parent pour qu’il coordonne, ie ordonnance, les enfants afin que aucun interblocage ne se produise. Chaque enfant sera relié au parent par un tube anonyme sur lequel il attendra l’indication qu’il peut commencer à acquérir les fourchettes. Lorsque l’enfant a fini, il envoie un signal SIGUSR1 au parent pour signaler qu’il a fini. On pourra utiliser un ordonnancement de type “tourniquet”.

Que peut-on dire de l’efficacité de cette solution en terme de parallélisme ? Pouvez-vous proposer une solution plus efficace si NB=6 ?