web-dev-qa-db-fra.com

Python. 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 à plusieurs reprises 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 incre():
    global count 
    lock.acquire()
    try:
        count += 1    
    finally:
        lock.release()

def bye():
    while True:
        incre()

def hello_there():
    while True:
        incre()

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

    while True:
        print count

if __== '__main__':
    main()

Donc, j'ai deux threads, les deux essayant d'incrémenter le compteur. Je pensais que si le thread 'A' appelé incre(), le lock était établi, empêchant ainsi l'accès de B jusqu'à la sortie de 'A'.

En cours d'exécution, il est clair que ce n'est pas le cas. Vous obtenez toutes les incréments aléatoires de données aléatoires.

Comment exactement l'objet verrou est-il utilisé?

Modifier, en outre, j'ai essayé de mettre les verrous à l'intérieur des fonctions du fil, mais toujours pas de chance.

54
Zack

Vous pouvez voir que vos verrous fonctionnent assez bien lorsque vous les utilisez, si vous ralentissez le processus et les bloquez un peu plus. Vous avez eu la bonne idée, en entourant les éléments de code critiques avec le verrou. Voici un petit ajustement de votre exemple pour vous montrer comment chacun attend l'autre pour libérer 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 __== '__main__':
    main()

Exemple de sortie:

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