2009-11-23 17 views
6

He escrito una aplicación (utilizando Delphi 2009) que permite al usuario seleccionar una serie de consultas que se pueden ejecutar en una serie de sistemas diferentes. Para permitir que las consultas se ejecuten simultáneamente, cada consulta se ejecuta en su propio hilo, utilizando un objeto TADOQuery. Todo esto funciona bienAplicación multiproceso (TThread) Delphi no terminará

El problema que tengo es cuando trato de cerrar la aplicación cuando todavía se está ejecutando una consulta (y, por lo tanto, hay un hilo separado activo). Cuando creo cada hilo, grabo THandle del hilo en una matriz. Cuando intento cerrar la aplicación, si todavía hay algún subproceso en ejecución, recupero el identificador del subproceso y lo paso a TerminateThread, que en teoría debería finalizar el subproceso y permitir que se cierre la aplicación. Sin embargo, esto no sucede. Se desencadena el evento onClose de la forma principal y parece que la aplicación se está cerrando, pero el proceso permanece activo y aparece mi interfaz Delphi como si la aplicación aún se estuviera ejecutando (es decir, el botón "Ejecutar" gris, depuración, etc.). No devuelvo el control a Delphi hasta que termine el proceso manualmente (ya sea Ctrl-F2 en Delphi o a través del Administrador de tareas).

Estoy usando TerminateThread porque la consulta puede tomar mucho tiempo para ejecutarse (unos minutos en casos en que estamos tratando con un millón de registros, que en el entorno del usuario final es perfectamente posible) y mientras está en ejecución, a menos que esté equivocado, el hilo no podrá verificar la propiedad Terminated y, por lo tanto, no podrá terminar si se estableció en True hasta que la consulta haya regresado, por lo que no puedo finalizar el hilo de la forma habitual (es decir, verificando la propiedad Terminated). Puede ser que el usuario quiera salir de la aplicación mientras se está ejecutando una consulta grande, y en ese caso, necesito que la aplicación finalice inmediatamente (es decir, todos los subprocesos en ejecución finalicen inmediatamente) en lugar de forzarlos a esperar hasta que todas las consultas tengan terminado de ejecutarse, por lo que TerminateThread sería ideal pero en realidad no está terminando el hilo!

¿Alguien puede ayudar aquí? ¿Alguien sabe por qué TerminateThread no funciona correctamente? ¿Alguien puede sugerir algo para que los subprocesos ejecuten grandes consultas de ADO para que finalicen inmediatamente?

Gracias por su ayuda!

Respuesta

8

Debería poder cancelar una consulta ADO conectando el evento OnFetchProgress y estableciendo la variable Eventstatus en esCancel. Esto debería provocar que su consulta finalice y permita que el hilo se cierre correctamente sin tener que recurrir al uso de TerminateThread.

+0

Esto parece el camino a seguir. He estado trabajando en otra cosa durante la última semana, pero lo investigaré en los próximos días. ¿Tienes un ejemplo de alguna fuente para esto? – Jeedee

5

Como puede leer en el msdn usando TerminateThread es peligroso.

TerminateThread es una función peligrosa que sólo debe ser utilizado en los casos más extremos. Usted debe llamada TerminateThread sólo si sabe exactamente lo que el subproceso de destino es haciendo, y permite controlar todo el código que el subproceso de destino posiblemente podría estar en funcionamiento en el momento de la terminación .

Pero también es muy eficaz en matar a los hilos. ¿Estás seguro de que tienes razón en tus conclusiones? Tal vez el hilo se mata, pero otro hilo todavía se está ejecutando? Tal vez sus manijas no son mangos de hilo? ¿Podrías mostrarnos algún código? O aún mejor: ¿un pequeño ejemplo de trabajo que podríamos probar por nosotros mismos?

+0

Soy consciente de la advertencia sobre el uso de TerminateThread, pero han explicado mis razones para hacerlo anteriormente. La aplicación se cierra bien cuando no se han iniciado subprocesos para ejecutar consultas, pero no se cierra cuando tengo un único subproceso en ejecución, por lo que definitivamente es el hilo de consulta que está causando el problema. Creo el hilo de consulta y almaceno el manejador en una matriz como esta: newThread: = TQueryThread.create (true); threadStatusArr [index] .threadHandle: = newThread.handle; newthread.resume; Luego recupero el identificador de la matriz y lo paso a TerminateThread. – Jeedee

6

En lugar de utilizar subprocesos con TADOQuery, tal vez debería considerar utilizar las opciones asíncronas de ADO.

ADOQuery1.ExecuteOptions := [eoAsyncExecute, eoAsyncFetch, eoAsyncFetch]; 

Luego, cuando su aplicación de cerca, se puede llamar:

ADOQuery1.cancel; 
+0

Ya he escrito la aplicación usando hilos. Tardaría demasiado tiempo en reescribir las consultas para hacerlo así, desafortunadamente, y no estoy seguro de que funcionaría como yo quisiera de todos modos. – Jeedee

Cuestiones relacionadas