Ceci est une ancienne révision du document !
A priori, quand on lance des threads, on s'attend à ce qu'ils agissent sans qu'on puisse déterminer dans quel ordre ils vont le faire.
Dans certains cas, nous voulons au contraire qu'ils agissent dans un ordre bien déterminé.
Voilà un exemple de solution possible.
Le principe est simple:
- on créé une variable globale “statut” initialisé à 1, et chaque thread pourra la lire et la modifier
- on créé le verrou “vstatut” (threading.Lock()) qui ne permettra l'accès à la variable “statut” par les threads qu'un à la fois.
- chaque thread attend, en lisant “statut”, que ce soit à son tour d'agir, et change “statut” à la fin pour que le suivant puisse agir à son tour.
Pour l'exemple, on a créé 10 threads, et leur action consiste simplement à imprimer leur nom sur la console.
#!/usr/bin/python # -*- coding: utf-8 -*- import threading import time ############################################################################### class Acteur(threading.Thread): def __init__(self, nom, st1, st2): threading.Thread.__init__(self) self.setName(nom) self.st1 = st1 # = statut qui déclenche l'action self.st2 = st2 # = statut pour passer la main au thread suivant self.marche = True # drapeau pour stopper le thread à la demande def run(self): global statut, vstatut, vprint while self.marche: # attente du bon statut avant l'action prévue: while True: vstatut.acquire() if statut==self.st1 or not self.marche: vstatut.release() break vstatut.release() time.sleep(0.1) # action prévue par le thread if self.marche: vprint.acquire() print "action faite par " + self.getName() vprint.release() # fin de l'action: le thread passe la main au suivant vstatut.acquire() statut=self.st2 vstatut.release() def stop(self): self.marche = False ############################################################################### print "debut" # création de la variable globale partagée statut et de son verrou statut = 1 vstatut = threading.Lock() # création d'un verrou pour l'impression par les thread vprint = threading.Lock() # creation d'une liste de thread nbacteurs = 10 acteurs = [] for i in xrange(0,nbacteurs): if i==(nbacteurs-1): k = 0 else: k = i+1 a = Acteur("A%d" % i, i, k) a.setDaemon(True) acteurs.append(a) # lancement de tous les threads for i in xrange(0,nbacteurs): acteurs[i].start() # attente 5 secondes time.sleep(5) # arrêt de tous les threads vprint.acquire() for i in xrange(0,nbacteurs): acteurs[i].stop() print "stopper le thread " + acteurs[i].getName() print "fini" vprint.release() # attente pour terminer que tous les threads soient arrêtés for i in xrange(0,nbacteurs): acteurs[i].join()
Ce programme affiche:
debut action faite par A1 action faite par A2 action faite par A3 action faite par A4 action faite par A5 action faite par A6 action faite par A7 action faite par A8 action faite par A9 action faite par A0 action faite par A1 action faite par A2 action faite par A3 action faite par A4 ... ... ... action faite par A5 action faite par A6 action faite par A7 action faite par A8 action faite par A9 action faite par A0 action faite par A1 action faite par A2 action faite par A3 stopper le thread A0 stopper le thread A1 stopper le thread A2 stopper le thread A3 stopper le thread A4 stopper le thread A5 stopper le thread A6 stopper le thread A7 stopper le thread A8 stopper le thread A9 fini