est-ce une bonne utilisation de stimuler les variables de condition?
J'ai écrit le programme suivant pour sinon incrémenter et doublement un compteur(incrément de première) à l'aide de stimuler les variables de condition. Quelqu'un peut-il me dire si c'est la bonne utilisation de stimuler les variables de condition. Il fonctionne correctement. Je ne comprends pas l'utilisation de la serrure dans l'attente de l'appel de fonction. Ce n'condition.attendre(lock)? Par exemple, quelle est l'utilisation des deux l'étendue des verrous dans l'augmentation et de se multiplier dans ce programme. Comment puis-je les éviter?
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int counter=0;
boost::mutex m1,m2;
bool incremented=false,multiplied=false;
boost::condition_variable c1,c2;
void Increment()
{
{
boost::mutex::scoped_lock lk(m1);
counter++;
incremented = true;
c1.notify_one();
while(!multiplied)
c2.wait(lk);
multiplied=false;
}
}
void Multiply()
{
{
boost::mutex::scoped_lock lk(m2);
while(!incremented)
c1.wait(lk);
incremented = false;
counter = counter*2 ;
multiplied = true;
c2.notify_one();
}
}
void IncrementNtimes(int n){
for(int i=0;i<n;i++){
Increment();
}
}
void MultiplyNtimes(int n){
for(int i=0;i<n;i++){
Multiply();
}
}
int main(int argc, char* argv[])
{
srand ( time(NULL) );
boost::thread thrd1(boost::bind(&IncrementNtimes,20));
boost::thread thrd2(boost::bind(&MultiplyNtimes,20));
thrd1.join();
thrd2.join();
cout<<"Main counter is:"<<counter<<endl;
return 0;
}
OriginalL'auteur Kamal | 2010-01-29
Vous devez vous connecter pour publier un commentaire.
Non, ce n'est pas correct. Vous y êtes presque, mais le gros problème est que les Multiplier et d'Incrément de la fonction à l'aide de la même mutex.
Un mutex est un objet qui fournit de l'EXclusion Mutuelle. En d'autres termes, le point d'un mutex est d'empêcher que deux threads par le toucher de la même variable dans le même temps et en provoquant des résultats imprévisibles. Un mutex est comme une sorte de jeton qu'un seul thread à la fois possède que donne le "droit" d'accéder à une variable (ou d'un ensemble de variables). Dans ce cas, la variable que vous essayez de protéger est
counter
. Il doit y avoir un et un seul mutex qui contrôle le droit d'accèscounter
. Dans votre cas, chaque thread va tenir son propre jeton qu'il pense lui donne le droit d'accès au compteur, et donc il y aura un comportement imprévisible.Vous "tenir" un mutex en le verrouillant. C'est le point de la serrure, et c'est pourquoi vous ne pouvez pas "éviter". Tout le point de l'étendue de serrures, c'est que, en supposant que vous n'avez qu'un mutex
m
, lorsque l'un des threads détient le verrou surm
, l'autre thread est garantie de ne pas être aussi un verrou surm
. Si vous avez codé correctement, le maintien d'un verrou surm
devrait être une condition préalable pour l'accès àcounter
, et donc la valeur decounter
devrait être prévisible.Maintenant, concernant le
wait()
. Un appel àwait()
signifie "j'abandonne la serrure sur ce mutex jusqu'à ce que quelqu'un d'autre signaux de cette condition, et puis je veux revenir". Dans le même temps, le fil s'arrête. Donc, en supposant que vous n'avez qu'un mutexm
et une conditionc
, etlk
est un verrou surm
, la lignec.wait(lk)
signifie que le thread va abandonner la serrurelk
surm
et puis suspendre l'exécution jusqu'à ce qu'un autre thread appellec.notify_one()
(ouc.notify_all()
). Lorsque le thread en attente de retour de l'appel àwait()
, il sera automatiquement re-gagné la serrurelk
surm
et est donc autorisé à accéder àcounter
de nouveau.Enfin, ces dynamiser les verrous sont limités serrures. Cela signifie qu'ils sont libérés automatiquement sur la destruction (quand ils sortent du champ d'application). Donc dans ce cas, chaque fonction est titulaire d'une serrure jusqu'à la sortie, sauf pour les moments où il a renoncé à sa serrure à attendre et a suspendu l'exécution dans l'attente d'un signal.
OriginalL'auteur Tyler McHenry
Serrures sont liés à des variables de condition, puisque les variables de condition sont apatrides - si Un thread signaux quand il n'y a pas de serveurs, et le fil B, puis entre dans une attente, B ne sera pas réveillé. Pour cette raison, il doit y avoir de l'état qui est liée à la variable d'état (dans ce cas, incrémenté et multiplié.) Le verrou protège cet état d'être consulté sur plusieurs threads. Lorsque vous passez la serrure à wait(), wait va automatiquement libérer le verrou et d'attendre sur la variable de condition, et acquérir la serrure lorsque la file d'attente des retours. Cela signifie qu'il n'y a pas de fenêtre, où l'état derrière la variable de condition pourrait avoir changé et l'attente se produit.
Par exemple, si la variable de condition n'était pas lié à une serrure:
+1, C'est le point!
OriginalL'auteur Michael
Variable de Condition doit toujours être associée à un verrou. La chose à réaliser est que vous devez être maintenant le verrou de l'appel en attente(), mais une fois à l'intérieur wait() le verrouillage est libéré. Lorsque vous signal, vous devez également être maintenant le verrou, et, enfin, l'attente coutume de retour (même après que le signal) jusqu'à ce que le signaleur libère le verrou.
OriginalL'auteur dicroce