Le code suivant contient une impasse potentielle, mais semble nécessaire: Pour copier en toute sécurité les données sur un conteneur d'un autre, les deux conteneurs doivent être verrouillés pour empêcher les modifications de se produire dans un autre thread.
void foo::copy(const foo & rhs)
{
pMutex->lock();
rhs.pMutex->lock();
// do copy
}
6 Réponses :
imposer une sorte d'ordre total sur les instances de Une autre approche consiste à utiliser la sémantique fonctionnelle et à écrire un Si votre code fait beaucoup de verrouillage, vous aurez peut-être besoin d'un algorithme d'évitement de blocage complexe tel que le L'algorithme du banquier . P> foo code> et d'acquérir toujours leurs serrures dans l'ordre croissant ou décroissant, par exemple, par exemple em>, FOO1-> verrouillage () code> puis foo2-> verrouillage () code>. p>
FOO :: clone code> méthode crée une nouvelle instance plutôt que de clouer un existant. P>
Même quelque chose d'aussi simple que les adresses de ce VS RHS travailleraient. Toujours verrouiller celui-ci avec l'adresse inférieure en premier.
Le clone ne fonctionnerait bien que s'il ne copie pas, et je ne pense pas que le partage implicite fonctionnera, mais je vais jeter un coup d'œil. Approche intéressante Kyle. Je ne peux voir aucun défaut.
C'est une bonne solution pour lui suggérer de faire une copie temporaire des données. std :: verrouillage code> offre déjà un tel algorithme d'évitement de blocage. et serait plus lisible
Que diriez-vous de cela?
void foo::copy(const foo & rhs)
{
scopedLock lock(rhs.pMutex); // release mutex in destructor
foo tmp(rhs);
swap(tmp); // no throw swap locked internally
}
Pour éviter une impasse, c'est probablement le meilleur, d'attendre que les deux ressources puissent être verrouillées:
Ne sais pas quelle API mutex que vous utilisez, donc ici est un pseudo pseudo arbitraire, supposons que Can_Lock () Code > Seulement des chèques si cela peut verrouiller un mutex, et que try_lock () code> renvoie true si elle était verrouillée et false, si le mutex est déjà verrouillé par quelqu'un d'autre. P> void foo::copy(const foo & rhs)
{
for(;;)
{
if(! pMutex->cany_lock() || ! rhs.pMutex->cany_lock())
{
// Depending on your environment call or dont call sleep()
continue;
}
if(! pMutex->try_lock())
continue;
if(! rhs.pMutex->try_lock())
{
pMutex->try_lock()
continue;
}
break;
}
// do copy
}
Pour éviter une impasse, il est préférable d'introduire un Livelock? Et tourner, en utilisant 100% cpu?
Vous pouvez essayer de verrouiller les mautexes simultanément à l'aide de SCOPED_LOCK ou Auto_Lock .... comme le transfert bancaire do ...
void Transfer(Receiver recv, Sender send)
{
scoped_lock rlock(recv.mutex);
scoper_lock slock(send.mutex);
//do transaction.
}
Ceci est une recette pour le désastre
Ceci est un problème connu déjà il y a une solution STD.
std :: scoped_lock propose une enveloppe Raii pour cette fonction et est
Généralement préféré à un appel nu à STD :: Verrouiller. P>
blockQuote>
Bien sûr, cela n'autorise pas vraiment les premières sorties d'un verrouillage au-dessus de l'autre alors utilisez STD :: LOCK () CODE> peut être appelé sur 2 ou plusieurs mutex en même temps tout en évitant l'impasse.
Plus d'informations ici
Il offre une recommandation. P>
std :: défer_lock code> ou std :: adopt_lock code> comme je l'ai fait dans cette < Un href = "https://stackoverflow.com/a/54713794/1943599"> répondez à une question similaire. P>
Comme @Melleter mentionné, vous pouvez utiliser mais note pour vérifier que std :: verrouillage code> pour verrouillage plusieurs mutiles en évitant l'impasse. rhs Code> n'est pas un * Ceci code> car dans ce cas std :: verrouillage code> conduira à UB due au même mordex. p> p>
Toute raison pour laquelle vous ne feriez pas std :: unique_lock std :: defer_lock code> puis effectuez std :: verrouillage (verrouillage) , L2); code>? Ou est-ce juste une préférence personnelle / style?
STD :: LOCK CODE> A un algorithme d'évitement Deadlock, passe-t-il les mautexes et il sera plus lisible aux autres que de la mise en œuvre de votre choix.