2011-03-03 2 views
15

question rapide, je l'espère ...Python conditionnel "" Lock design

Je suis en train de faire un peu de verrouillage partagé en utilisant des déclarations

def someMethod(self, hasLock = False): 
    with self.my_lock: 
     self.somethingElse(hasLock=True) 


def somethingElse(self, hasLock = False): 
    #I want this to be conditional... 
    with self.my_lock: 
      print 'i hate hello worlds" 

qui ont du sens? Je ne veux essentiellement faire avec le IF * Je n'ai pas déjà le verrou ..

En plus d'être en mesure d'accomplir cela, est-ce un mauvais design? Devrais-je simplement acquérir/me libérer?

Cela semble être une de ces questions pètent du cerveau ..

+1

Il a une odeur de code. – zzzzBov

+0

Plus maintenant, je vais utiliser RLock – Nix

Répondre

30

Il suffit d'utiliser un threading.RLock qui est rentrant ce qui signifie qu'il peut être acquis plusieurs fois par le même fil.

http://docs.python.org/library/threading.html#rlock-objects

Pour plus de clarté, le RLock est utilisé dans les with déclarations, tout comme dans votre exemple de code:

lock = threading.RLock() 

def func1(): 
    with lock: 
     func2() 

def func2(): 
    with lock: # this does not block even though the lock is acquired already 
     print 'hello world' 

En ce qui concerne si oui ou non c'est une mauvaise conception, nous aurions besoin plus de contexte. Pourquoi les deux fonctions ont besoin d'acquérir le verrou? Quand est func2 appelé par autre chose que func1?

+1

la possibilité d'utiliser l'instruction with élimine beaucoup de code de plaque de chaudière ... – Nix

+0

Peu importe, cela fonctionne parfaitement. Merci. – Nix

+1

@Nix "Tous les objets fournis par ce module qui ont des méthodes acquire() et release() peuvent être utilisés comme gestionnaires de contexte pour une instruction with." –

0

Utilisation avec la déclaration est mieux que seulement acquire() et release() fonctions. De cette façon, si une erreur se produit, les verrous seront libérés.

+0

Pouvez-vous faire avec conditionnellement? – Nix

+0

Vous ne pouvez pas effectuer d'instructions conditionnelles, mais certains objets prennent en charge l'affectation via with statement. Par exemple 'avec open (" x.txt ") comme f: print f.read()' –

0

L'instruction with est une excellente façon d'implémenter le verrouillage, car le verrouillage est un modèle parfait d'acquisition de ressources. Cependant, votre exemple actuel ne fonctionnera pas, vous aurez besoin d'une instruction if autour de l'instruction with dans somethingElse().

4

Le Python or est short circuiting afin que vous puissiez faire le verrouillage conditionnel:

def somethingElse(self, hasLock = False): 
    #I want this to be conditional... 
    with hasLock or self.my_lock: 
      print 'i hate hello worlds' 

Malheureusement, il est pas tout à fait aussi simple que cela, car un booléen n'est pas un retour valide d'une déclaration with. Vous devez créer une classe avec les valeurs __enter__ et __exit__ pour inclure la valeur booléenne True.

Voici une implémentation possible que je n'ai pas testée.

from contextlib import contextmanager 

@contextmanager 
def withTrue(): 
    yield True 

def withbool(condition): 
    if condition: 
     return withTrue() 
    return False 

def somethingElse(self, hasLock = False): 
    with withbool(hasLock) or self.my_lock(): 
      print 'i hate hello worlds' 

Ceci est beaucoup de passe-partout pour quelque chose de si simple, alors la solution RLock semble être un gagnant. Cette solution pourrait être utile dans un contexte différent.

+0

Ce serait un bon moment pour utiliser [contextmanager] (http://docs.python.org/library/contextlib.html#contextlib.contextmanager). –

+1

Je pense que cela fonctionnerait, mais RLock fait ce dont j'ai besoin hors de la boîte. Merci. – Nix

+0

@jleedev, merci, j'ai oublié de contextmanager. Malheureusement, je ne pense pas que cela fonctionnerait dans ce contexte puisque vous voulez seulement envelopper la valeur vraie, pas le faux. –

1

Pourquoi ne pas:

def someMethod(self): 
    with self.my_lock: 
     self.somethingNoLock() 

def somethingElse(self): 
    with self.my_lock: 
     self.somethingNoLock() 

def somethingNoLock(self): 
    print 'i hate hello worlds" 

Notez que si someMethod et somethingElse sont identiques dans ma solution, en général, ils seraient différentes. Vous pouvez placer un autre wrapper autour de somethingNoLock afin que l'acquisition et la libération du verrou ne soient pas répétées plusieurs fois.

Ceci est beaucoup plus simple et direct. Tout simplement parce que le marteau à verrouillage rentrant est disponible, je ne recommanderais pas de l'utiliser quand il y a une façon plus directe et moins fragile de le clouer.

La critique plus spécifique de rlock est que la ligne qui crée le verrou rentrant est très éloignée du code qui acquiert le verrou de manière réentrante. Ceci est légèrement fragile si quelqu'un dit coalesce le verrou rentrant avec un autre verrou qui n'est pas rentrant ou change autrement la ligne qui crée le verrou.