Ir al contenido


Foto

TthreadedQueue: falla al tiempo, probable causante la clase tmonitor


  • Por favor identifícate para responder
5 respuestas en este tema

#1 Gronfi

Gronfi

    Member

  • Miembros
  • PipPip
  • 25 mensajes

Escrito 24 febrero 2018 - 11:50

Hola compañeros.

Quería preguntaros si os suena el asunto.

Estoy usando esta clase que para implementar cosas del tipo publicador/subcriptor y está muy bien, aunque creo que tiene un bug al hacer el grow cosa que ya he reportado a Emba a ver que dicen,pero tras tener bastantes horas trabajando la aplicación con bastantes threads haciendo pops y algunos threads haciendo push, empieza a funcionar mal el asunto (también lo he reportado, pero a saber si hay respuesta). El problema es que a priori se puede configurar que al hacer el pop y el push, le puedes decir que timeout debe aplicar dejando ese hilo dormido entre tanto. Está genial, todo se dicho, si funciona bien...porque al de horas dándole caña, el concepto del timeout deja de funcionar, no duerme el tiempo marcado, provocando que los hilos pasen a consumir toda la cpu ya que no se produce ningún tipo de sleep. No hay un patrón, sin más en un momento dado empieza a suceder. He podido debuggar, por eso he visto que eso es lo que sucede, y todo apunta a que quien empieza a funcionar mal es la clase tmonitor que es a la que se llama para hacer la espera. 

¿A alguno os suena el asunto?


  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 24 febrero 2018 - 12:10

En éstos casos lo mejor es hacer uso de un log donde vayas encerrando el problema, aunque yo comenzaría por revisar si se está liberado correctamente los threads.

 

Saludos


  • 0

#3 Gronfi

Gronfi

    Member

  • Miembros
  • PipPip
  • 25 mensajes

Escrito 24 febrero 2018 - 01:03

Hola!

Gracias por responder.

Los threads no se terminan o cierran cuando el problema sucede. Siguen vivos pues en teoría no tienen que terminar, solo que están mal funcionando debido a que van a todo gas ya que de repente deja de funcionar el wait que hace el tmonitor dentro del objeto TThreadeQueue cuando se le llama al pop (en definitiva que se quede a la espera/dormido durante un tiempo a que llegue algo y sino al del tiempo da el timeout).

Tengo logs por todos lados que me centraron en que el tema estaba por aquí, lo he visto debuggando que falla aquí (tengo puesto que se queden los threads infinitamente en el pop pero salen todos los threads al instante sin que se haya hecho ningún push). Todo sucede a partir de un momento, afecta a un grupo de threads, más adelante en el tiempo afecta a otro grupo de threads, y así sigue. Lo que hay en común entre todos es el tmonitor que es la tripa de la clase.

El tmonitor tiene la función wait que espera que haya eventos o que llegue el timeout. Al debuggar pude llegar hasta aquí, pero ahí ya es código que bufffff complicado saber que pasa y por qué:

function TMonitor.Wait(ALock: PMonitor; Timeout: Cardinal): Boolean;
var
RecursionCount: Integer;
WaitingThread: TWaitingThread;
begin
WaitingThread.Next := nil;
WaitingThread.Thread := ALock.CheckOwningThread;
// This event should probably be cached someplace.
// Probably not on the instance since this is a per-thread-per-instance resource
WaitingThread.WaitEvent := MonitorSupport.NewWaitObject;
try
// Save the current recursion count for later
RecursionCount := ALock.FRecursionCount;
// Add the current thread to the waiting queue
QueueWaiter(WaitingThread);
// Set it back to almost released so the next Exit call actually drops the lock
ALock.FRecursionCount := 1;
// Now complete the exit and signal any waiters
ALock.Exit;
// Get in line for someone to do a Pulse or PulseAll
Result := MonitorSupport.WaitOrSignalObject(nil, WaitingThread.WaitEvent, Timeout) = WAIT_OBJECT_0;
// Got to get the lock back and block waiting for it.
ALock.Enter(INFINITE);
// Remove any dangling waiters from the list
RemoveWaiter(WaitingThread);
// Lets restore the recursion to return to the proper nesting level
ALock.FRecursionCount := RecursionCount;
finally
MonitorSupport.FreeWaitObject(WaitingThread.WaitEvent);
end;
end;

 

 

El problema empieza en la linea:

WaitingThread.WaitEvent := MonitorSupport.NewWaitObject;

pues devuelve 'nil', y en la llamada posterior

Result := MonitorSupport.WaitOrSignalObject(nil, WaitingThread.WaitEvent, Timeout) = WAIT_OBJECT_0;

sale de la función como un rayo pues no hay handle para el timeout claro...Entrando a la función MonitorSupport.NewWaitObject es donde ya no queda claro como va la cosa porque es código raro del system.pas que además si no debuggas no sabes llegar a él pues si lo buscas en diseño conduce a punteros a funciones...en fin...

 

La sensación es como si se le gastara la posibilidad de asignar más eventos de espera, y ello apunta a que puede ser que el TMonitor no los libera bien, quiero pensar.

No es por lanzar balones fuera, pero la aplicación a priori solo hace push y pop, y crea al inicio y destruye al final los objetos, así que no creo que haya algo que hace el código que he metido para provocarlo, aunque nunca se sabe.

No tengo claro como enfocar el tema. Solo se le ocurre hacer una prueba en limpio con un thread que hace pops y otro que hace push, tenerlo a todo trapo, ver si pasa lo mismo al de x horas. si es así es claro que el asunto es algún bug del tmonitor. En caso de que no suceda, ya apunta a que alguna otra parte de la aplicación le afecta al tmonitor


  • 0

#4 Gronfi

Gronfi

    Member

  • Miembros
  • PipPip
  • 25 mensajes

Escrito 25 febrero 2018 - 11:30

Hola de nuevo.
 
He minimizado el comportamiento de la aplicación real a la minima expresión: unos threads que leen y otros que escriben.
El problema aparece tarde o temprano, y va afectando a grupos de threads (en un momento afecta a 4, en otro a otros x,...y así hasta terminar afectando a todos). Todo depende de la caña que las aplicaciones tengan, las que tengo yo tienen mucha (por desgracia para lo que comentamos)  y no es más que un asunto de tiempo. La clase TMonitor está en el centro del asunto y las llamadas al wait ante todo (que es lo que hace por dentro el tthreadedqueue), que acaba fallando. Subo luego la aplicación de test por si queréis verlo, hay que tenerlo un rato (hay una constante de threads para subir o bajar la caña, se podrían cambiar otras variables como los timeout pero bueno lo dejé así para parecerse al comportamiento real de la aplicación). La aplicación con un define permite utilizar el TThreadedQueue que trae el compilador u otra clase que hereda del mismo que cree para parchear el método Grow (que tiene bug y lo parcheé como pude, ya subí el probable bug a Embarcadero) y añadir 2 métodos para usar timeouts dinámicos para los métodos popitem y pushitem. He hecho pruebas con las dos no sea que la que cambié metiera ruido...sé que no pero más bale ser cauto y humilde ejem... XD
Subiré todo esto a Embarcadero como QC y a los foros a ver si alguien tiene algún parche temporal o lo arreglan en Embarcadero. Pinta a probable bug importante.

  • 0

#5 Gronfi

Gronfi

    Member

  • Miembros
  • PipPip
  • 25 mensajes

Escrito 25 febrero 2018 - 11:42

Hola. El proyecto de test. Es una aplicación de consola, se hace un setup, se lanzan los hilos, y están a todo gas dejando log en pantalla (caos de logs). Se pueden pausar e ir viendo si hay ya threads parados o no bajo petición de teclas y luego reanudar. Si os bajais el processexplorer podreis ir viendo como la aplicación se inicia con 31 threads y va bajando (supongo que con el admin de programas se podrá ver lo mismo pero me he acostumbrado al otro), ya que cuando se detecta que un hilo empieza a fallar (los timeouts son de tiempo 0) se terminan los hilos.

 

PD: hay que esperar un buen rato a que empiece a fallar...lo aviso para los nerviosos que esperen suceda en 10 segundos

Archivos adjuntos


  • 0

#6 Gronfi

Gronfi

    Member

  • Miembros
  • PipPip
  • 25 mensajes

Escrito 25 febrero 2018 - 12:43

Por si alguien quiere ver el QC:

https://quality.emba...rowse/RSP-19993


  • 0




IP.Board spam blocked by CleanTalk.