std::lock_guard exemple, expliquer pourquoi il fonctionne
J'ai atteint un point dans mon projet qui nécessite une communication entre les threads sur les ressources que peut-être bien écrit, donc la synchronisation est un must. Cependant je ne comprends pas vraiment la synchronisation à rien d'autre que le niveau de base.
Considère que le dernier exemple dans ce lien: http://www.bogotobogo.com/cplusplus/C11/7_C11_Thread_Sharing_Memory.php
#include <iostream>
#include <thread>
#include <list>
#include <algorithm>
#include <mutex>
using namespace std;
//a global variable
std::list<int>myList;
//a global instance of std::mutex to protect global variable
std::mutex myMutex;
void addToList(int max, int interval)
{
//the access to this function is mutually exclusive
std::lock_guard<std::mutex> guard(myMutex);
for (int i = 0; i < max; i++) {
if( (i % interval) == 0) myList.push_back(i);
}
}
void printList()
{
//the access to this function is mutually exclusive
std::lock_guard<std::mutex> guard(myMutex);
for (auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr ) {
cout << *itr << ",";
}
}
int main()
{
int max = 100;
std::thread t1(addToList, max, 1);
std::thread t2(addToList, max, 10);
std::thread t3(printList);
t1.join();
t2.join();
t3.join();
return 0;
}
L'exemple montre comment trois fils, deux écrivains et un lecteur accède à une ressource commune(liste).
Deux fonctions globales sont utilisées: l'une qui est utilisé par les deux threads d'écriture, et celle utilisée par le thread de lecture. Ces deux fonctions utilisent un lock_guard pour verrouiller la même ressource, la liste.
Maintenant, voici ce que j'ai juste ne peut pas envelopper la tête autour de: Le lecteur utilise un verrou dans un autre champ que les deux threads d'écriture, mais encore verrouille la même ressource. Comment cela peut-il fonctionner? Ma compréhension limitée des mutex se prête bien à l'écrivain de fonction, vous avez deux threads en utilisant la même fonction. Je peux comprendre que, une vérification est faite à droite lorsque vous êtes sur le point d'entrer dans la zone protégée, et si quelqu'un d'autre est déjà à l'intérieur, vous attendre.
Mais quand le champ est différent? Cela semble indiquer qu'il y a une sorte de mécanisme plus puissant que le processus lui-même, une sorte d'environnement d'exécution de blocage de l'exécution de la "fin" de thread. Mais je pensais qu'il n'y avait pas de telles choses en c++. Donc, je suis à une perte.
Ce qu'il se passe sous le capot?
OriginalL'auteur Deviatore | 2016-02-07
Vous devez vous connecter pour publier un commentaire.
myMutex
est global, qui est ce qui est utilisé pour protégermyList
.guard(myMutex)
simplement engage la serrure et la sortie du bloc qui provoque sa destruction, dis-engager le verrou.guard
est juste un moyen pratique de s'engager et de dis-engager le verrou.Avec cela de la manière,
mutex
ne protège pas toutes les données. Il fournit simplement un moyen pour protéger les données. C'est le modèle de conception qui protège les données. Si je vous écris de ma propre fonction pour modifier la liste ci-dessous, lamutex
ne peut pas la protéger.La serrure ne fonctionne que si toutes les parties du code qui ont besoin d'accéder aux données engager le verrou avant d'accéder et de se désengager après ils sont faits. Cette conception de motif de s'engager et de dis-engager le verrou avant et après chaque accès est ce qui protège les données (
myList
dans votre cas)Maintenant vous demander pourquoi utiliser
mutex
à tous, et pourquoi pas, disons, unbool
. Et oui vous pouvez, mais vous devez vous assurer que lebool
la variable de certaines caractéristiques, y compris mais non limité à la liste ci-dessous.Il existe différents
synchronization
mécanismes qui donnent "mieux verrouillage" (à travers le processus de rapport sur les threads, plusieurs processeur contre, seul processeur, etc) à un coût de "ralentissement de la performance", de sorte que vous devriez toujours choisir un mécanisme de verrouillage qui est tout juste suffisant pour votre situation.OriginalL'auteur Vikhram
Jetons un coup d'oeil à la ligne correspondante:
Avis que le
lock_guard
références de la mondiale mutexmyMutex
. C'est le même mutex pour tous les trois threads. Celock_guard
n'est en substance ceci:myMutex
et maintient une référence vers elle.myMutex
.Le mutex est toujours la même, il n'a rien à voir avec la portée. Le point de
lock_guard
est juste pour faire de verrouillage et de déverrouillage du mutex plus facile pour vous. Par exemple, si vous avez manuellementlock
/unlock
, mais votre fonction lève une exception, quelque part dans le milieu, il n'atteindra jamais leunlock
déclaration. Donc, le faire de la même façon manuelle vous assurez-vous que le mutex est toujours déverrouillé. D'autre part, lalock_guard
objet est détruit automatiquement à chaque fois que la fonction est sorti – peu importe comment il est terminé.Il est appelé le planificateur du système d'exploitation
Ce n'est pas vraiment à propos de l'encapsulation. Le mutex est essentiellement une ressource qui vous acquérir quand
lock()
est appelé. Si la ressource ne peut pas être acquis (parce qu'un autre thread est le tenant), ce qui se passe dépend de la mise en œuvre concrète; algorithmes d'exclusion mutuelle sont utilisés, ou le système d'exploitation gère, mettre votre fil sur une file d'attente (voir, par exemple, ce tutoriel sur les Threads POSIX Programmation pour les systèmes UNIX/Linux).OriginalL'auteur mindriot
C'est précisément ce qu'une serrure. Lorsqu'un thread prend la serrure, peu importe où dans le code il le fait, il doit attendre son tour si un autre thread détient le verrou. Lorsqu'un thread libère un verrou, peu importe où dans le code il le fait, un autre thread peut acquérir le verrou.
Verrous de protection des données, pas de code. Ils le font en s'assurant que tous code qui accède à des données protégées par le fait alors qu'il détient le verrou, à l'exclusion des autres threads de tout code qui peuvent avoir accès à ces mêmes données.
OriginalL'auteur David Schwartz