2010-10-27 28 views
0

S'il y a deux threads en tant que producteur/consommateur, il est bon d'avoir une ligne suivante pour éviter les blocages. Je suis au courant des verrous en direct, mais suppose qu'ils font beaucoup de travail avant d'appeler cette méthode Wait():Problème de prévention de blocage et de blocage de threads

// member variable 
object _syncLock = new object(); 

void Wait() 
{ 
    lock (_syncLock) 
     { 
     Monitor.Pulse(_syncLock); 
     Monitor.Wait(_syncLock); 
     } 
} 

Ici, il est impossible dans les deux fils soient état d'attente.

+0

Problème résolu en élargissant la portée de verrouillage et aveugle Wait() et Pulse() enlevé. Qu'est-ce que j'ai appris de Reed était ce pourquoi j'ai tellement de problèmes avec seulement deux fils et modèle connu de producteur/consommateur? Donc, redessiné en regardant une grande image. Le point était lorsque vous cherchez à coder dans Visual Studio, les lignes de code ont plus de sens que les cycles CPU, donc il est tentant de minimiser le temps de verrouillage alors que si ces lignes de code ne comparent rien à un changement de contexte. – Xaqron

Répondre

2

Cela semble trop compliqué. Juste gérer votre verrouillage correctement en premier lieu, et éviter le problème. Si vous avez seulement deux threads, et qu'ils essaient d'acquérir le même verrou simple (correctement), vous ne devriez pas avoir d'interblocages. Une impasse signifie qu'il se passe quelque chose d'autre ici. Cela dit, si vous avez la possibilité d'utiliser le TPL via .NET 4 (ou les extensions Rx sur .NET 3.5), vous pouvez envisager d'utiliser BlockingCollection<T> à la place. Il est idéal pour une utilisation dans un scénario producteur/consommateur et fonctionne de manière non verrouillée.

+0

L'impasse se produit lorsque la vitesse de production ou de consommation est très élevée. Par exemple, lorsque le producteur remplit la file et s'endort, la file d'attente devient vide et les deux threads restent en attente ou si le consommateur vérifie et qu'il n'y a rien à consommer juste avant qu'il ne dorme, le producteur remplit la file et les deux se mettent en veille. Je ne verrouillerai pas le produit entier ou ne consommerai pas d'instructions en raison de problèmes de performances. Le blocage de la collecte n'est pas bon pour un producteur/consommateur unique où la performance est importante. – Xaqron

+0

@ Xaqron: avez-vous réellement mesuré que l'introduction d'un verrou aurait un impact significatif sur les performances de votre application? Cela ressemble à une optimisation prématurée qui conduit à une conception plus compliquée. – BrokenGlass

+0

@Xaquon: BlockingCollection est en réalité le contraire - il est incroyablement bien optimisé pour un seul producteur, consommateur unique. Il est susceptible d'être beaucoup plus rapide que d'utiliser des verrous sur une collection standard, même si le verrouillage est minimal. –

1

Si votre intention est de créer une variante associé du motif producteur-consommateur, la séquence est Pulse avant Wait pour le producteur et Wait avant Pulse pour le consommateur. Vous pouvez référencer la figure 5 en Joe Duffy's article on this. Cependant, gardez à l'esprit que puisque sa mise en œuvre exécute un Wait inconditionnel dans la méthode Enqueue, un effet ping-pong se produira entre le producteur et le consommateur. La file d'attente, dans sa mise en œuvre, ne peut avoir qu'un seul élément par producteur. Donc, si c'est votre intention, alors votre billet. Sinon, vous pouvez l'adapter tel quel et appliquer une condition au Wait dans la méthode Enqueue pour qu'il se comporte davantage comme un vrai tampon FIFO.

Cependant, comme Reed, je me demande pourquoi BlockingCollection n'a pas pu être utilisé. Cette collection devrait être très efficace car elle utilise une stratégie sans verrou pour les méthodes Add et Take. Bien sûr, comme je l'ai mentionné ci-dessus, si vous voulez vraiment la variante appariée, alors cette collection ne répondra pas à vos exigences et vous devrez rouler la vôtre en utilisant Joe Duffy's comme point de départ.

Rappelez-vous simplement d'utiliser une boucle while au lieu d'un contrôle if avant d'appliquer l'attente. Monitor.Wait attend simplement un changement dans l'état de verrouillage et rien de plus, donc vous devez revérifier la condition d'attente.

+0

+1 pour l'ordre d'attente/d'impulsion producteur/consommateur. BlockingCollection n'est pas assez flexible pour moi, puisque je pulse producteur à différents points de consommation. Le blocage de la collection le ferait exploser dès qu'il y aurait de la place pour un autre objet pendant que je le laisserais me reposer pour mon scénario. – Xaqron

+0

@Xaqron: Vous devrez alors lancer votre propre file d'attente de blocage. –