94 votes

Python threading. Comment verrouiller un thread ?

J'essaie de comprendre les bases du threading et de la concurrence. Je veux un cas simple où deux threads essaient de manière répétée d'accéder à une ressource partagée.

Le code :

import threading

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()
count = 0
lock = threading.Lock()

def increment():
    global count 
    lock.acquire()
    try:
        count += 1    
    finally:
        lock.release()

def bye():
    while True:
        increment()

def hello_there():
    while True:
        increment()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)

    while True:
        print count

if __name__ == '__main__':
    main()

J'ai donc deux threads, qui essaient tous deux d'incrémenter le compteur. Je pensais que si le thread 'A' appelait increment() le lock serait établi, empêchant "B" d'accéder jusqu'à ce que "A" soit libéré.

Running the montre clairement que ce n'est pas le cas. Vous obtenez tous les incréments aléatoires de la course aux données.

Comment l'objet de verrouillage est-il utilisé exactement ?

De plus, j'ai essayé de placer les verrous à l'intérieur des fonctions du fil, mais toujours pas de chance.

127voto

jdi Points 38029

Vous pouvez constater que vos verrous fonctionnent à peu près comme vous les utilisez, si vous ralentissez le processus et les faites bloquer un peu plus. Vous avez eu la bonne idée d'entourer les parties critiques du code avec le verrou. Voici un petit ajustement à votre exemple pour vous montrer comment chacun attend que l'autre libère le verrou.

import threading
import time
import inspect

class Thread(threading.Thread):
    def __init__(self, t, *args):
        threading.Thread.__init__(self, target=t, args=args)
        self.start()

count = 0
lock = threading.Lock()

def incre():
    global count
    caller = inspect.getouterframes(inspect.currentframe())[1][3]
    print "Inside %s()" % caller
    print "Acquiring lock"
    with lock:
        print "Lock Acquired"
        count += 1  
        time.sleep(2)  

def bye():
    while count < 5:
        incre()

def hello_there():
    while count < 5:
        incre()

def main():    
    hello = Thread(hello_there)
    goodbye = Thread(bye)

if __name__ == '__main__':
    main()

Exemple de sortie :

...
Inside hello_there()
Acquiring lock
Lock Acquired
Inside bye()
Acquiring lock
Lock Acquired
...

-10voto

funny guru992 Points 5
import threading 

# global variable x 
x = 0

def increment(): 
    """ 
    function to increment global variable x 
    """
    global x 
    x += 1

def thread_task(): 
    """ 
    task for thread 
    calls increment function 100000 times. 
    """
    for _ in range(100000): 
        increment() 

def main_task(): 
    global x 
    # setting global variable x as 0 
    x = 0

    # creating threads 
    t1 = threading.Thread(target=thread_task) 
    t2 = threading.Thread(target=thread_task) 

    # start threads 
    t1.start() 
    t2.start() 

    # wait until threads finish their job 
    t1.join() 
    t2.join() 

if __name__ == "__main__": 
    for i in range(10): 
        main_task() 
        print("Iteration {0}: x = {1}".format(i,x))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X