En una aplicación de servidor tenemos lo siguiente: Una clase llamada JobManager que es un singleton. Otra clase, el Programador, que sigue comprobando si es el momento de agregar cualquier clase de trabajo al Administrador de trabajos.Explicación/solución de Deadlock Delphi
Cuando es el momento de hacerlo, el Programador de hacer algo como:
TJobManager.Singleton.NewJobItem(parameterlist goes here...);
Al mismo tiempo, en la aplicación cliente, el usuario haga algo que genera una llamada al servidor. Internamente, el servidor se envía un mensaje a sí mismo, y una de las clases que escuchan ese mensaje es el JobManager. El Administrador de tareas maneja el mensaje, y sabe que es el momento de añadir una nueva tarea a la lista, llamando a su propio método:
NewJobItem(parameter list...);
En el método NewJobItem, tengo algo como esto:
CS.Acquire;
try
DoSomething;
CallAMethodWithAnotherCriticalSessionInternally;
finally
CS.Release;
end;
Ocurre que el sistema llega a un punto muerto en este punto (CS.Acquire). La comunicación entre el cliente y la aplicación del servidor se realiza a través de Indy 10. Creo que la llamada RPC que activa el método de aplicación del servidor que envía un mensaje al JobManager se ejecuta en el contexto de Indy Thread.
El Programador tiene su propio hilo ejecutándose y realiza una llamada directa al método JobManager. ¿Esta situación es propensa a estancamientos? ¿Alguien me puede ayudar a entender por qué está pasando un punto muerto aquí?
Sabíamos que, a veces, cuando el cliente realizaba una acción específica que causaba que el sistema se bloqueara, finalmente pude descubrir este punto, donde la sección crítica de la misma clase se alcanza dos veces, desde diferentes puntos (el Programador y el método del manejador de mensajes del JobManager).
Algunos más información
Quiero añadir que (esto puede ser tonto, pero de todos modos ...) dentro de la HacerAlgo hay otra
CS.Acquire;
try
Do other stuff...
finally
CS.Release;
end;
Este CS.Release interna está haciendo cualquier cosa al CS externo. ¿Adquirir? Si es así, este podría ser el punto donde el Programador está ingresando a la Sección Crítica, y todo el bloqueo y desbloqueo se convierte en un desastre.
El propósito de una sección crítica es proteger el código que no se puede ejecutar al mismo tiempo en diferentes hilos, por lo que está bien si una sección crítica en la misma instancia se alcanza dos veces (o más) porque significa la sección crítica está haciendo su trabajo allí y ¡está diseñada para eso! Lo malo es cuando CS1 no se libera porque está adquiriendo subprocesos esperando para adquirir CS2, mientras que CS2 no se libera porque está adquiriendo subprocesos esperando adquirir CS1 (llamado un DeadLock). Por lo que dices, no estoy seguro de que estés en un punto muerto ... ¿por qué estás seguro? – jachguate
Al depurar, siguiendo el método del controlador de mensajes, acabo de ingresar a la sección crítica, y mi punto de interrupción en la línea CS.Acquire, fue alcanzado nuevamente, proveniente del programador: presionando F8 nuevamente, el sistema se detuvo. – ronaldosantana
También puede interbloquear en el bucle de manejo de mensajes de Windows.Cuando ThreadA tenía un bloqueo en CS1 y luego realiza una llamada que requiere que el bucle de mensaje se repita; y el hilo B está en efecto interrumpiendo, interrumpiendo o demorando indefinidamente el ciclo del mensaje mientras espera la adquisición de CS1 ... –