Al escribir aplicaciones multiproceso, uno de los problemas más comunes experimentados son los puntos muertos.
Mis preguntas a la comunidad son:
¿Qué es un punto muerto?
¿Cómo los detectas?
¿Los manejas?
Y finalmente, ¿cómo evitas que ocurran?
Al escribir aplicaciones multiproceso, uno de los problemas más comunes experimentados son los puntos muertos.
Mis preguntas a la comunidad son:
¿Qué es un punto muerto?
¿Cómo los detectas?
¿Los manejas?
Y finalmente, ¿cómo evitas que ocurran?
Respuestas:
Se produce un bloqueo cuando varios procesos intentan acceder al mismo recurso al mismo tiempo.
Un proceso pierde y debe esperar a que termine el otro.
Se produce un punto muerto cuando el proceso de espera todavía se está quedando con otro recurso que el primero necesita antes de que pueda finalizar.
Entonces, un ejemplo:
Los recursos A y B son utilizados por el proceso X y el proceso Y
La mejor manera de evitar puntos muertos es evitar que los procesos se crucen de esta manera. Reduzca la necesidad de bloquear todo lo que pueda.
En las bases de datos, evite realizar muchos cambios en diferentes tablas en una sola transacción, evite los desencadenantes y cambie a lecturas optimistas / sucias / nolock tanto como sea posible.
Permítanme explicar un ejemplo del mundo real (no realmente real) para una situación de punto muerto de las películas de crimen. Imagine que un criminal tiene un rehén y, contra eso, un policía también tiene un rehén que es amigo del criminal. En este caso, el criminal no va a dejar ir al rehén si el policía no deja que su amigo lo deje ir. Además, el policía no va a dejar ir al amigo del criminal, a menos que el criminal libere al rehén. Esta es una situación interminable y poco confiable, porque ambas partes están insistiendo en el primer paso el uno del otro.
Entonces, simplemente, cuando dos hilos necesitan dos recursos diferentes y cada uno de ellos tiene el bloqueo del recurso que el otro necesita, es un punto muerto.
Estás saliendo con una chica y un día después de una discusión, ambas partes están desconsoladas y esperando una llamada de " Lo siento, perdí y te perdí" . En esta situación, ambas partes quieren comunicarse entre sí si y solo si una de ellas recibe una llamada de disculpa de la otra. Debido a que ninguno de los dos va a comenzar la comunicación y esperará en un estado pasivo, ambos esperarán a que el otro inicie la comunicación que termina en una situación de punto muerto.
Los puntos muertos solo ocurrirán cuando tengas dos o más bloqueos que se puedan adquirir al mismo tiempo y se agarren en un orden diferente.
Las formas de evitar tener puntos muertos son:
Para definir un punto muerto, primero definiría el proceso.
Proceso : Como sabemos, el proceso no es más que una program
ejecución.
Recurso : Para ejecutar un proceso de programa se necesitan algunos recursos. Las categorías de recursos pueden incluir memoria, impresoras, CPU, archivos abiertos, unidades de cinta, CD-ROM, etc.
Punto muerto : el punto muerto es una situación o condición en la que dos o más procesos retienen algunos recursos e intentan adquirir algunos más, y no pueden liberarlos hasta que terminen su ejecución.
Condición o situación de punto muerto
En el diagrama anterior hay dos procesos P1 y p2 y hay dos recursos R1 y R2 .
El recurso R1 se asigna al proceso P1 y el recurso R2 se asigna al proceso p2 . Para completar la ejecución del proceso, P1 necesita el recurso R2 , por lo que P1 solicita R2 , pero R2 ya está asignado a P2 .
Del mismo modo, el proceso P2 para completar su ejecución necesita R1 , pero R1 ya está asignado a P1 .
ambos procesos no pueden liberar su recurso hasta que completen su ejecución y, a menos que lo hagan. Así que ambos esperan otros recursos y esperarán para siempre. Entonces esta es una condición de DEADLOCK .
Para que se produzca un punto muerto, deben cumplirse cuatro condiciones.
y todas estas condiciones se cumplen en el diagrama anterior.
Un punto muerto ocurre cuando un hilo está esperando algo que nunca ocurre.
Por lo general, ocurre cuando un subproceso está esperando un mutex o semáforo que nunca fue liberado por el propietario anterior.
También ocurre con frecuencia cuando tienes una situación que involucra dos hilos y dos bloqueos como este:
Thread 1 Thread 2
Lock1->Lock(); Lock2->Lock();
WaitForLock2(); WaitForLock1(); <-- Oops!
Generalmente los detecta porque las cosas que espera que sucedan nunca suceden, o la aplicación se bloquea por completo.
Puedes echar un vistazo a estos maravillosos artículos , en la sección Punto muerto . Está en C # pero la idea sigue siendo la misma para otra plataforma. Cito aquí para facilitar la lectura
Un punto muerto ocurre cuando dos subprocesos cada uno espera un recurso en poder del otro, por lo que ninguno puede continuar. La forma más fácil de ilustrar esto es con dos bloqueos:
object locker1 = new object();
object locker2 = new object();
new Thread (() => {
lock (locker1)
{
Thread.Sleep (1000);
lock (locker2); // Deadlock
}
}).Start();
lock (locker2)
{
Thread.Sleep (1000);
lock (locker1); // Deadlock
}
El punto muerto es un problema común en los problemas de multiprocesamiento / multiprogramación en el sistema operativo. Digamos que hay dos procesos P1, P2 y dos recursos compartibles globalmente R1, R2 y en la sección crítica ambos recursos necesitan ser accedidos
Inicialmente, el sistema operativo asigna R1 para procesar P1 y R2 para procesar P2. Como ambos procesos se ejecutan simultáneamente, pueden comenzar a ejecutar su código, pero el PROBLEMA surge cuando un proceso llega a la sección crítica. Por lo tanto, el proceso R1 esperará a que el proceso P2 libere R2 y viceversa ... Entonces esperarán para siempre (CONDICIÓN DE DESBLOQUEO).
Una pequeña analogía ...
Tu madre (SO),
tú (P1),
tu hermano (P2),
manzana (R1),
cuchillo (R2),
sección crítica (cortar manzana con cuchillo).Tu madre te da la manzana y el cuchillo a tu hermano al principio.
Ambos están contentos y jugando (ejecutando sus códigos).
Cualquiera de ustedes quiere cortar la manzana (sección crítica) en algún momento.
No quieres darle la manzana a tu hermano.
Tu hermano no quiere darte el cuchillo.
Así que ambos esperarán mucho, mucho tiempo :)
El punto muerto ocurre cuando dos hilos adquieren bloqueos que impiden que cualquiera de ellos progrese. La mejor manera de evitarlos es con un desarrollo cuidadoso. Muchos sistemas integrados protegen contra ellos mediante el uso de un temporizador de vigilancia (un temporizador que restablece el sistema cada vez que se cuelga durante un cierto período de tiempo).
Un punto muerto se produce cuando hay una cadena circular de subprocesos o procesos que contienen un recurso bloqueado y tratan de bloquear un recurso retenido por el siguiente elemento de la cadena. Por ejemplo, dos hilos que sostienen respectivamente el bloqueo A y el bloqueo B, y ambos intentan adquirir el otro bloqueo.
Un programa clásico y muy simple para comprender la situación de Deadlock : -
public class Lazy {
private static boolean initialized = false;
static {
Thread t = new Thread(new Runnable() {
public void run() {
initialized = true;
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(initialized);
}
}
Cuando el hilo principal invoca Lazy.main, comprueba si la clase Lazy se ha inicializado y comienza a inicializar la clase. El subproceso principal ahora se establece inicializado en falso, crea e inicia un subproceso en segundo plano cuyo método de ejecución establece inicializado en verdadero y espera a que se complete el subproceso en segundo plano.
Esta vez, la clase está siendo inicializada por otro hilo. En estas circunstancias, el subproceso actual, que es el subproceso de fondo, espera en el objeto Clase hasta que se completa la inicialización. Desafortunadamente, el hilo que está haciendo la inicialización, el hilo principal, está esperando que se complete el hilo de fondo. Debido a que los dos subprocesos ahora se están esperando, el programa está DESBLOQUEADO.
Un punto muerto es un estado de un sistema en el que ningún proceso / subproceso único es capaz de ejecutar una acción. Como lo mencionaron otros, un punto muerto suele ser el resultado de una situación en la que cada proceso / subproceso desea adquirir un bloqueo a un recurso que ya está bloqueado por otro (o incluso el mismo) proceso / subproceso.
Existen varios métodos para encontrarlos y evitarlos. Uno está pensando mucho y / o probando muchas cosas. Sin embargo, lidiar con el paralelismo es notoriamente difícil y la mayoría (si no todas) las personas no podrán evitar por completo los problemas.
Algunos métodos más formales pueden ser útiles si se toma en serio el tratamiento de este tipo de problemas. El método más práctico que conozco es utilizar el enfoque teórico del proceso. Aquí puede modelar su sistema en algún lenguaje de proceso (por ejemplo, CCS, CSP, ACP, mCRL2, LOTOS) y utilizar las herramientas disponibles para (modelar) verificar los puntos muertos (y quizás también algunas otras propiedades). Ejemplos de herramientas para usar son FDR, mCRL2, CADP y Uppaal. Algunas almas valientes podrían incluso demostrar que sus sistemas están libres de puntos muertos mediante el uso de métodos puramente simbólicos (prueba de teoremas; busque Owicki-Gries).
Sin embargo, estos métodos formales generalmente requieren cierto esfuerzo (por ejemplo, aprender los conceptos básicos de la teoría de procesos). Pero supongo que eso es simplemente una consecuencia del hecho de que estos problemas son difíciles.
El punto muerto es una situación que ocurre cuando hay menos cantidad de recursos disponibles según lo solicitado por el proceso diferente. Significa que cuando el número de recursos disponibles es menor de lo solicitado por el usuario, en ese momento el proceso pasa a la espera. Algunas veces la espera aumenta más y no hay ninguna posibilidad de verificar el problema de falta de recursos. Esta situación se conoce como punto muerto. En realidad, el punto muerto es un problema importante para nosotros y solo ocurre en el sistema operativo multitarea.
Por encima algunas explicaciones son agradables. Espero que esto también sea útil: https://ora-data.blogspot.in/2017/04/deadlock-in-oracle.html
En una base de datos, cuando una sesión (p. Ej., Ora) quiere un recurso retenido por otra sesión (p. Ej., Datos), pero esa sesión (datos) también quiere un recurso retenido por la primera sesión (ora). También puede haber más de 2 sesiones involucradas, pero la idea será la misma. En realidad, los puntos muertos impiden que algunas transacciones continúen funcionando. Por ejemplo: supongamos que ORA-DATA mantiene el bloqueo A y solicita el bloqueo B Y el SKU mantiene el bloqueo B y solicita el bloqueo A.
Gracias,
El punto muerto ocurre cuando un hilo está esperando que otro hilo termine y viceversa.
¿Como evitar?
- Evite bloqueos anidados
- Evite bloqueos innecesarios
- Use hilo unirse ()
¿Cómo lo detectas?
ejecuta este comando en cmd:
jcmd $PID Thread.print
referencia : geeksforgeeks
Los puntos muertos no solo ocurren con bloqueos, aunque esa es la causa más frecuente. En C ++, puede crear un punto muerto con dos hilos y sin bloqueos simplemente haciendo que cada llamada de hilo se una () en el objeto std :: thread para el otro.
El uso del bloqueo para controlar el acceso a los recursos compartidos es propenso a puntos muertos, y el planificador de transacciones por sí solo no puede evitar que ocurran.
Por ejemplo, los sistemas de bases de datos relacionales usan varios bloqueos para garantizar las propiedades ACID de la transacción .
No importa qué sistema de base de datos relacional esté utilizando, siempre se adquirirán bloqueos al modificar (por ejemplo, UPDATE
o DELETE
) un determinado registro de tabla. Sin bloquear una fila que fue modificada por una transacción actualmente en ejecución, Atomicity se vería comprometida .
Como expliqué en este artículo , se produce un punto muerto cuando dos transacciones simultáneas no pueden avanzar porque cada una espera que la otra libere un bloqueo, como se ilustra en el siguiente diagrama.
Debido a que ambas transacciones están en la fase de adquisición de bloqueo, ninguna libera un bloqueo antes de adquirir la siguiente.
Si está utilizando un algoritmo de Control de concurrencia que se basa en bloqueos, siempre existe el riesgo de ejecutarse en una situación de bloqueo. Los puntos muertos pueden ocurrir en cualquier entorno de concurrencia, no solo en un sistema de base de datos.
Por ejemplo, un programa de subprocesos múltiples puede llegar a un punto muerto si dos o más subprocesos están esperando bloqueos que se adquirieron previamente para que ningún subproceso pueda avanzar. Si esto sucede en una aplicación Java, la JVM no puede forzar a un Thread a detener su ejecución y liberar sus bloqueos.
Incluso si la Thread
clase expone un stop
método, ese método ha quedado en desuso desde Java 1.1 porque puede hacer que los objetos se dejen en un estado inconsistente después de que se detiene un subproceso. En cambio, Java define un interrupt
método, que actúa como una pista, ya que un hilo que se interrumpe puede simplemente ignorar la interrupción y continuar su ejecución.
Por esta razón, una aplicación Java no puede recuperarse de una situación de punto muerto, y es responsabilidad del desarrollador de la aplicación ordenar las solicitudes de adquisición de bloqueo de tal manera que nunca se produzcan puntos muertos.
Sin embargo, un sistema de base de datos no puede imponer una orden de adquisición de bloqueo dado, ya que es imposible prever qué otros bloqueos querrá adquirir una determinada transacción. Preservar el orden de bloqueo se convierte en responsabilidad de la capa de acceso a datos, y la base de datos solo puede ayudar a recuperarse de una situación de punto muerto.
El motor de la base de datos ejecuta un proceso separado que escanea el gráfico de conflicto actual en busca de ciclos de bloqueo-espera (que son causados por puntos muertos). Cuando se detecta un ciclo, el motor de la base de datos selecciona una transacción y la cancela, haciendo que se liberen sus bloqueos, para que la otra transacción pueda progresar.
A diferencia de la JVM, una transacción de base de datos está diseñada como una unidad atómica de trabajo. Por lo tanto, una reversión deja la base de datos en un estado consistente.
Para obtener más detalles sobre este tema, consulte también este artículo .
Mutex en esencia es un candado, que proporciona acceso protegido a recursos compartidos. En Linux, el tipo de datos de mutex de subproceso es pthread_mutex_t. Antes de usar, inicialízalo.
Para acceder a los recursos compartidos, debe bloquear el mutex. Si el mutex ya está en la cerradura, la llamada bloqueará el hilo hasta que se desbloquee el mutex. Al finalizar la visita a los recursos compartidos, debe desbloquearlos.
En general, hay algunos principios básicos no escritos:
Obtenga el bloqueo antes de usar los recursos compartidos.
Sosteniendo la cerradura el menor tiempo posible.
Libere el bloqueo si el hilo devuelve un error.