Bonjour à tous,
je me mets doucement à Pyhton, notamment grâce au livre "Introducing Python" de Bill Lubanovic aux éditions O'reilly.
Ce dernier présente l'utilisation des threads sous python via le module
threading. C'est une présentation assez sommaire et j'ai voulu la tester un peu, notamment au regard du fonctionnement des pthreads en C.
Mon objectif est donc de créer deux threads sous Python qui vont chacun lire et incrémenter une variable commune n. Le programme sera écrit de manière à ce que les deux threads se marchent volontairement sur les pieds, mettant ainsi en évidence la nécessité d'un mécanisme de lock. (c'est un exemple adapté du livre "Développement système sous Linux" de Christophe Blaess aux éditions Eyrolles).
Mon code :
import threading as th
from time import sleep
n = 0
def traitement(k):
if k==1: # premier thread
wait_time = 2
else:
wait_time = 1
print("- [THREAD %d] je lis la valeur n=%d, je vais l'incrémenter de 1..." %(k, n))
sleep(wait_time)
n=n+1
print('- [THREAD %d] done ! désormais n = %d !' %(k, n))
# Création de deux threads
for k in range(2): # [0, 1]
d_thread = th.Thread(target=traitement, args=(k+1,))
print('- [PERE] Lancement du thread %d...' % (k+1))
d_thread.start()
Hélas ça plante, j'obtiens :
- [PERE] Lancement du thread 1...
- [PERE] Lancement du thread 2...
Exception in thread Thread-53:
Traceback (most recent call last):
File "/home/donut/anaconda3/envs/donut/lib/python3.8/threading.py", line 932, in _bootstrap_inner
Exception in thread Thread-54self.run()
File "/home/donut/anaconda3/envs/donut/lib/python3.8/threading.py", line 870, in run
:
Traceback (most recent call last):
File "/home/donut/anaconda3/envs/donut/lib/python3.8/threading.py", line 932, in _bootstrap_inner
self._target(*self._args, **self._kwargs)
File "/home/donut/python/test/test_chap11.py", line 85, in traitement
print("- [THREAD %d] je lis la valeur n=%d, je vais l'incrémenter de 1..." %(k, n))
UnboundLocalError: local variable 'n' referenced before assignment
self.run()
File "/home/donut/anaconda3/envs/donut/lib/python3.8/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "/home/donut/python/test/test_chap11.py", line 85, in traitement
print("- [THREAD %d] je lis la valeur n=%d, je vais l'incrémenter de 1..." %(k, n))
UnboundLocalError: local variable 'n' referenced before assignment
Je comprends que les threads n'ont pas accès à la variable n, qui est pourtant définie au tout début du main...
C'est un comportement étrange puisque, par exemple, l'appel à la fonction print_a() ci-dessous fonctionnera correctement :
a = 10
def print_a():
print("a = %d" % a)
print_a()
Je m'en sors en rajoutant un "global n" dans la définition de la fonction traitement()
def traitement(k):
global n
if k==1: # premier thread
wait_time = 2
else:
wait_time = 1
print("- [THREAD %d] je lis la valeur n=%d, je vais l'incrémenter de 1..." %(k, n))
sleep(wait_time)
n=n+1
print('- [THREAD %d] done ! désormais n = %d !' %(k, n))
Néanmoins, je ne comprends pas bien... il me semblait que les threads manipulaient exactement les mêmes variables que celles visibles lors de leur lancement... j'ai loupé quelque chose ?
Merci d'avance 🙂
D.