Esiste un modo ampiamente noto di bloccare più blocchi, che si basa sulla scelta di ordini lineari fissi e blocchi di acquisizione in base a questo ordine.Strategie di blocco mutex multiple e perché le librerie non utilizzano il confronto degli indirizzi
Questo è stato proposto, ad esempio, nella risposta per "Acquire a lock on two mutexes and avoid deadlock". Soprattutto, la soluzione basata sul confronto degli indirizzi sembra essere abbastanza elegante ed evidente.
Quando ho provato a verificare come è effettivamente implementato, ho trovato, con mia sorpresa, che questa soluzione non è molto utilizzata.
Per citare il Kernel Docs - Unreliable Guide To Locking:
Libri di testo vi dirà che se si blocca sempre nello stesso ordine, è sarà mai ottenere questo tipo di situazione di stallo. La pratica ti dirà che questo approccio non è scalabile: quando creo un nuovo blocco, non capisco il numero del kernel per capire dove si trova nella gerarchia di blocchi 5000 .
Pthread non sembra avere un tale meccanismo integrato a tutti.
Boost.Thread venuta soluzione completamente differente, lock()
per multiple (da 2 a 5) mutex si basa sul tentativo e bloccaggio altrettanti mutex quanto è possibile al momento.
Questo è il frammento del codice sorgente Boost.Thread (Boost 1.48.0, boost/filetto/locks.hpp: 1291):
template<typename MutexType1,typename MutexType2,typename MutexType3>
void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3)
{
unsigned const lock_count=3;
unsigned lock_first=0;
for(;;)
{
switch(lock_first)
{
case 0:
lock_first=detail::lock_helper(m1,m2,m3);
if(!lock_first)
return;
break;
case 1:
lock_first=detail::lock_helper(m2,m3,m1);
if(!lock_first)
return;
lock_first=(lock_first+1)%lock_count;
break;
case 2:
lock_first=detail::lock_helper(m3,m1,m2);
if(!lock_first)
return;
lock_first=(lock_first+2)%lock_count;
break;
}
}
}
dove lock_helper
rendimenti 0
sul successo e il numero di mutex che non sono stati chiusi con successo altrimenti.
Perché questa soluzione è migliore, rispetto al confronto di indirizzi o altri tipi di ID? Non vedo alcun problema con il confronto tra puntatori, che può essere evitato usando questo tipo di blocco "cieco".
Ci sono altre idee su come risolvere questo problema a livello di libreria?
Ho trovato un thread interessante qui: https://groups.google.com/d/topic/comp.programming.threads/iyZ-0UcR7bw/discussion –
I deadlock reali sono causati da alcune funzioni che hanno acquisito un blocco lungo fa e molto lontano. Questo schema non offre alcuna protezione contro questo. –