c++ - sintaxis - serie fibonacci programacion
¿Cuándo usar mutex recursivo? (5)
Entiendo que el mutex recursivo permite que el mutex se bloquee más de una vez sin llegar a un punto muerto y debe desbloquearse la misma cantidad de veces. Pero, ¿en qué situaciones específicas necesitas usar un mutex recursivo? Estoy buscando situaciones de diseño / nivel de código.
Los mutexes recursivo y no recursivo tienen diferentes casos de uso . Ningún tipo de mutex puede reemplazar fácilmente al otro. Los mutexes no recursivos tienen menos sobrecarga, y los mutex recursivos tienen en algunas situaciones semánticas útiles o incluso necesarias y en otras situaciones semánticas peligrosas o incluso rotas. En la mayoría de los casos, alguien puede reemplazar cualquier estrategia usando mutexes recursivos con una estrategia diferente más segura y más eficiente basada en el uso de mutexes no recursivos.
- Si solo desea excluir otros subprocesos del uso de su recurso protegido mutex, entonces podría usar cualquier tipo de exclusión mutua , pero podría querer usar el mutex no recursivo debido a su sobrecarga más pequeña.
- Si desea llamar funciones recursivamente, que bloquean el mismo mutex, entonces tampoco
- tiene que usar un mutex recursivo , o
- tiene que desbloquear y bloquear el mismo mutex no recursivo una y otra vez (¡cuidado con los hilos concurrentes!) (suponiendo que esto sea semánticamente sólido, aún así podría ser un problema de rendimiento), o
- tiene que anotar de alguna manera qué mutexes ya bloquearon (simulando propiedad recursiva / mutexes).
- Si desea bloquear varios objetos protegidos por mutex a partir de un conjunto de dichos objetos, donde los conjuntos podrían haberse generado al fusionarse, puede elegir
- usar por objeto exactamente un mutex , permitiendo que más hilos funcionen en paralelo, o
- usar por objeto una referencia a cualquier mutex recursivo posiblemente compartido , para disminuir la probabilidad de no bloquear todos los mutex juntos, o
- usar por objeto una referencia comparable a cualquier mutex no recursivo posiblemente compartido , eludiendo la intención de bloquear varias veces.
- Si desea liberar un bloqueo en un hilo diferente de lo que ha sido bloqueado, entonces tiene que usar bloqueos no recursivos (o bloqueos recursivos que permiten explícitamente esto en lugar de lanzar excepciones).
- Si desea utilizar variables de sincronización , debe poder desbloquear explícitamente el mutex mientras espera en cualquier variable de sincronización, de modo que el recurso pueda ser utilizado en otros hilos. Eso solo es posible con mutexes no recursivos , ya que los repetidores recursivos ya podrían haber sido bloqueados por el llamador de la función actual.
Me encontré con la necesidad de un mutex recursivo hoy, y creo que es quizás el ejemplo más simple entre las respuestas publicadas hasta el momento: esta es una clase que expone dos funciones API, Proceso (...) y Restablecer ().
public void Process(...)
{
acquire_mutex(mMutex);
// Heavy processing
...
reset();
...
release_mutex(mMutex);
}
public void reset()
{
acquire_mutex(mMutex);
// Reset
...
release_mutex(mMutex);
}
Ambas funciones no deben ejecutarse al mismo tiempo porque modifican las partes internas de la clase, por lo que quería usar un mutex. El problema es que Process () llama a reset () internamente, y crearía un interbloqueo porque mMutex ya está adquirido. Bloquearlos con un bloqueo recursivo en su lugar soluciona el problema.
Por ejemplo, cuando tiene una función que lo llama recursivamente, y desea obtener acceso sincronizado a él:
void foo() {
... mutex_acquire();
... foo();
... mutex_release();
}
sin un mutex recursivo, primero tendría que crear una función de "punto de entrada", y esto resulta engorroso cuando tiene un conjunto de funciones mutuamente recursivas. Sin mutex recursivo:
void foo_entry() {
mutex_acquire(); foo(); mutex_release(); }
void foo() { ... foo(); ... }
Si desea ver un ejemplo de código que usa mutex recursivas, consulte las fuentes de "Electric Fence" para Linux / Unix. Fue una de las herramientas comunes de Unix para encontrar "límites comprobando" los excesos y excesos de lectura / escritura, así como el uso de la memoria que se ha liberado, antes de que llegara Valgrind .
Simplemente compile y vincule la cerca eléctrica con las fuentes (opción -g con gcc / g ++), y luego vincule con su software con la opción de enlace -lefence, y comience a recorrer las llamadas a malloc / free.
Sin duda sería un problema si un hilo bloqueado tratando de adquirir (de nuevo) un mutex que ya poseía ...
¿Hay alguna razón para no permitir que un mutex sea adquirido varias veces por el mismo hilo?