1
votes

Est-ce correct si je déverrouille un mutex avant de le verrouiller?

J'ai écrit du code avant mais je me suis rendu compte qu'il avait un très mauvais style de code alors je l'ai changé.

J'ai changé le A.unlock à l'intérieur du bloc if. Je sais que si le si jamais exécuté, ce fil déverrouillera le mutex qui n'appartient pas à lui-même, puis il renverra un comportement indéfini. Ma question est la suivante: si cela renvoie un comportement indéfini, la logique fonctionnera-t-elle toujours ici? Parce que si le thread t1 n'avait pas le verrou, t1 déverrouiller le mutex A renverra un comportement indéfini et le mutex sera toujours détenu par le thread qui le tient droit? Et cela n'affectera pas l'autre logique de ce code. Mon ancien code fonctionne de la même manière que je place la partie de déverrouillage à l'intérieur du bloc if. C'est pourquoi je suis curieux de savoir comment cela peut fonctionner.

mutex A;
if(something)
{
A.lock();
}
A.unlock();


6 commentaires

" Ma question est, si elle renvoie un comportement non défini, la logique ici fonctionnera-t-elle toujours? " Comprenez-vous ce qu'est un "comportement non défini"? Si le code présente un comportement indéfini, la norme ne donne aucune garantie sur l'exactitude de votre code. Cela peut sembler fonctionner, par accident, bien sûr. Il n'y a tout simplement aucune garantie que cela continuera à fonctionner.


C'est ce que je pense. Parce qu'avant, ce mauvais code fonctionnait parfaitement comme prévu. S'il y avait des milliers de bogues, nous remarquerions immédiatement cette partie de mauvais code. Il semble que le code fonctionne correctement.


" S'il y avait des milliers de bogues, nous remarquerions immédiatement cette partie de mauvais code. " Le code qui présente un comportement indéfini est un bogue. La seule façon de l'éviter est de ne pas écrire le code qui présente un comportement indéfini. Puisque, en théorie, il n'y a aucun moyen de détecter 100% des cas de comportement indéfini (les analyseurs de code statique peuvent cependant aider un peu).


Merci mais je ne suis pas sûr que "fonctionne" signifie ici. Vous voulez dire que le code peut fonctionner ou que le déverrouillage peut fonctionner, de sorte qu'il peut déverrouiller le mutex qui est détenu par un autre thread?


Si votre code dépend du comportement indéfini (UB), cela pourrait fonctionner pour vous, ... sur votre ordinateur, ... aujourd'hui, ... lorsque vous utilisez le compilateur que vous utilisez maintenant, ... avec ceux-ci mêmes options, ... et vous l'exécutez sur la version exacte du système d'exploitation que vous utilisez actuellement, ... etc .; mais changer l'une de ces choses pourrait l'empêcher de fonctionner. Le pire, c'est lorsque vous avez testé le **** de votre logiciel, puis que vous l'avez expédié à des milliers de clients, puis six mois ou un an plus tard, Microsoft envoie une mise à niveau de Windows et votre logiciel s'arrête. travaille pour tout le monde .


Double possible du comportement indéfini, non spécifié et défini par l'implémentation


4 Réponses :


2
votes

Vous devriez envisager d'utiliser std :: lock_guard :

mutex A;
if (something)
{
    lock_guard<mutex> lock(A);
}


0 commentaires

2
votes

Lorsque vous appelez unlock sur un mutex, le mutex doit être appartenant au thread actuel ou le comportement n'est pas défini. Un comportement non défini signifie que tout peut arriver, y compris le programme qui semble fonctionner correctement, le programme plante ou la mémoire ailleurs est corrompue et un problème n'est visible que plus tard.

Normalement, un mutex n'est pas utilisé directement; l'une des autres classes standard (comme std :: unique_lock < / a> ou std :: lock_guard sont utilisé pour le gérer. Vous n'aurez plus à vous soucier du déverrouillage du mutex.


3 commentaires

Donc, il est possible après avoir exécuté A.unlock (), il a déverrouillé A qui est détenu par un autre thread?


@GavinXu Non. Si un autre thread a verrouillé le mutex, essayer de le déverrouiller sera un comportement indéfini.


Donc, le code que j'ai écrit ci-dessus peut provoquer un bogue de mémoire ou faire planter le programme directement mais ne pas déverrouiller le mutex si le bloc if-else ne s'exécute jamais? Je pense avoir la raison pour laquelle je n'ai pas trouvé ça avant. s'ils ne déverrouillent pas d'autres threads, c'est ce à quoi nous nous attendions: si le bloc if-else s'exécute, il sera déverrouillé après le bloc if. si le bloc ne s'exécute jamais, le comportement indéfini n'affectera pas les autres threads et ce thread ne contient pas non plus le mutex. donc nos anciens cas de test n'ont pas pu le trouver.



0
votes

C'est un comportement indéfini pour déverrouiller un mutex vous ne l'avez pas verrouillé. Cela peut fonctionner dans certains cas plusieurs fois, mais un jour, il se cassera et se comportera différemment.

Vous pouvez utiliser un lock_guard dans votre cas et oubliez le verrouillage / déverrouillage

std::lock_guard<std::mutex> lock(A);


0 commentaires

0
votes

La norme ISO C ++ a ceci à dire à ce sujet, dans [thread.mutex.requirements.mutex] (je souligne):

L'expression m.unlock () doit être bien formée et avoir la sémantique suivante:

Requiert: le thread appelant sera propriétaire du mutex.

Cela signifie que ce que vous faites est une violation de la norme et n'est donc pas défini. Cela peut fonctionner, ou il peut supprimer tous vos fichiers pendant la lecture du fichier derisive_maniacal_laughter.mp3 :-)

En bout de ligne, ne le faites pas .

Je ne mettrais pas non plus le unlock dans la boucle car le C ++ moderne a des mécanismes de plus haut niveau pour gérer la libération automatique des ressources. Dans ce cas, c'est un garde-cadenas:

std::mutex mtxProtectData; // probably defined elsewhere (long-lived)
: : :
if (dataNeedsChanging) {
    std::lock_guard<std::mutex> mtxGuard(mtxProtectData);
    // Change data, mutex will unlock at brace below
    //   when mtxGuard goes out of scope.
}


0 commentaires