2010-02-12 5 views
9

Le code suivant contient un blocage potentiel, mais semble nécessaire: pour copier en toute sécurité les données dans un conteneur d'un autre, les deux conteneurs doivent être verrouillés pour empêcher les modifications dans un autre thread. Foo a un conteneur STL et "do copy" consiste essentiellement à utiliser std :: copy. Comment verrouiller les deux mutex sans introduire de blocage?Acquérir un verrou sur deux mutex et éviter les interblocages

Répondre

15

Impose une sorte de commande totale sur les instances de foo et acquiert toujours leurs verrous dans l'ordre croissant ou décroissant, par exemple., foo1->lock() puis foo2->lock().

Une autre approche consiste à utiliser une sémantique fonctionnelle et à écrire à la place une méthode foo::clone qui crée une nouvelle instance plutôt que de tabasser une instance existante.

Si votre code effectue beaucoup de verrouillage, vous aurez peut-être besoin d'un algorithme complexe d'évitement de blocage, tel que le banker's algorithm.

+0

Même quelque chose d'aussi simple que les adresses de ce contre rhs travaillerait. toujours verrouiller celui avec l'adresse inférieure en premier. –

+0

clone ne fonctionnerait bien que s'il ne copiait pas, et je ne pense pas que le partage implicite fonctionnera, mais je vais jeter un coup d'oeil. Approche intéressante Kyle. Je ne peux pas voir les défauts. – pomeroy

1

Que pensez-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 
} 

Ceci est une exception sûre, et assez bien sûr aussi. Pour être 100% thread, vous aurez besoin de revoir tout le chemin du code et de re-examiner à nouveau avec un autre ensemble d'yeux, après l'examiner à nouveau ...

-1

Pour éviter une impasse, c'est probablement mieux, d'attendre jusqu'à à la fois les ressources peuvent être verrouillées:

ne sais pas quelle API mutex que vous utilisez est donc ici un code pseudo arbitraire, supposons que can_lock() vérifie uniquement si elle peut verrouiller un mutex, et que try_lock() renvoie true si elle a fait serrure, et faux , si le mutex est déjà verrouillé par quelqu'un d'autre.

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 
} 
+2

Pour éviter un blocage, il est préférable d'introduire un livelock? Et tourner, en utilisant 100% CPU? – bk1e

-1

Vous pouvez verrouiller les deux mutex en même temps en utilisant scoped_lock ou auto_lock .... comme faire le virement bancaire ...

void Transfer(Receiver recv, Sender send) 
{ 
    scoped_lock rlock(recv.mutex); 
    scoper_lock slock(send.mutex); 

    //do transaction. 
} 
Questions connexes