Outils pour utilisateurs

Outils du site


thread_lock

Synchroniser plusieurs threads avec un verrou

Comme j'ai mis un certain temps à comprendre comment fonctionnaient les verrous, je mets ici un exemple simple qui le montre bien.

A l'origine, je me suis inspiré d'un exemple de l'excellent site http://wikipython.flibuste.net/moin.py/QuestionsGenerales

Un verrou est une classe du module theading qui permet à chaque thread de demander l'autorisation avant d'utiliser une ressource commune.

Dans l'exemple ci-dessous, on a un thread qui incrémente une variable globale, et un autre thread qui la décrémente. Quand les 2 threads ont terminé, la variable doit être nulle. Ce n'est pas le cas si on n'a pas fait de synchronisation, parce que les threads ont pu intervenir en même temps sur la variable, ce qui entraine un résultat aléatoire.

On créé un verrou en instanciant la classe Lock() de threading:

verrou = threading.Lock()

Quand l'un des threads veut modifier la variable globale, il demande l'autorisation par:

verrou.acquire()

ce qui le bloque jusqu'à ce que l'autre thread ait terminé son opération.

Quand il a obtenu l'autorisation (=l'autre thread a relâché le verrou), il modifie la variable globale et relâche le verrou par:

verrou.release()

Ce qui permettra à l'autre thread d'accéder à la variable.

En fait, c'est le programmeur qui a décidé que le verrou “verrou” est affecté à l'utilisation de la variable globale x. Il n'y a pas d'autre liaison fonctionnelle entre le verrou “verrou” et les threads.

Voilà le code:

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
# inspiré de http://wikipython.flibuste.net/moin.py/QuestionsGenerales
 
import threading
import sys
 
x = 0
n = 1000
 
def fnadd() :
    global x,verrou
    for i in xrange(n) :
        verrou.acquire()
        x += 1
        verrou.release()
 
def fnsub() :
    global x,verrou
    for i in xrange(n) :
        verrou.acquire()
        x -= 1
        verrou.release()
 
verrou = threading.Lock()
t1=threading.Thread(target=fnadd)
t2=threading.Thread(target=fnsub)
t1.start()
t2.start()
t1.join()
t2.join()
print "Valeur finale de la variable x = ", x

Ce qui est intéressant dans ce mécanisme de verrou, c'est qu'on voit bien que cela permettra de construire des objets de communication plus complexes comme une pile, une file d'attente ou même comme un “tableau blanc”, dans lequel chaque thread peut envoyer des messages aux autres, et chaque thread peut en prendre connaissance et agir en conséquence.

C'est la voie royale pour des simulations d'ateliers industriels, ou de processus vivants, ou même pour des procédés de calculs répartis sur plusieurs ordinateurs avec régulation de charge (load balancing), etc…

Je sens qu'il y aura bientôt des développements de ce genre sur ce site, parce que tous ces problèmes m'intéressent beaucoup :-D .

Amusez-vous bien!

thread_lock.txt · Dernière modification: 2008/04/27 07:32 par tyrtamos

Outils de la page