Existe una forma ampliamente conocida de bloquear bloqueos múltiples, que se basa en elegir el orden lineal fijo y los bloqueos que requieren de acuerdo con este orden.Estrategias de bloqueo de múltiples mutex y por qué las bibliotecas no usan la comparación de direcciones
Eso fue propuesto, por ejemplo, en la respuesta para "Acquire a lock on two mutexes and avoid deadlock". Especialmente, la solución basada en la comparación de direcciones parece ser bastante elegante y obvia.
Cuando traté de comprobar cómo se implementa realmente, he encontrado, para mi sorpresa, que esta solución no se usa ampliamente.
citar el Kernel Docs - Unreliable Guide To Locking:
libros de texto le dirá que si siempre se bloquea en el mismo orden, que nunca conseguir este tipo de estancamiento. La práctica le dirá que este enfoque no escala: cuando creo un nuevo bloqueo, no entiendo suficiente del kernel para averiguar en qué parte de la jerarquía de 5000 bloqueos se ajustará .
PThreads ello no le parece a tienen un mecanismo de este tipo construida en en absoluto.
Boost.Thread ocurrió solución completamente diferente, lock()
para múltiples (2 a 5) mutex se basa en tratar y bloquear la mayor cantidad de exclusiones mutuas, ya que es posible por el momento.
Este es el fragmento del código fuente Boost.Thread (Boost 1.48.0, realce/hilo/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;
}
}
}
donde lock_helper
rendimientos 0
sobre el éxito y el número de mutexes que no se bloquearon con éxito de lo contrario.
¿Por qué esta solución es mejor, que la comparación de direcciones o cualquier otro tipo de identificadores? No veo ningún problema con la comparación de punteros, que se puede evitar con este tipo de bloqueo "a ciegas".
¿Hay alguna otra idea sobre cómo resolver este problema a nivel de biblioteca?
He encontrado un hilo interesante aquí: https://groups.google.com/d/topic/comp.programming.threads/iyZ-0UcR7bw/discussion –
Los bloqueos reales son causados por alguna función que adquirió un bloqueo largo Hace y muy lejos. Este esquema no ofrece protección contra eso. –