Página 1 de 1

Trabajado con Future's

Publicado: Lun Abr 20, 2020 4:24 pm
por bingen
Buenas Xailer Team, estoy probando ya los nuevos Futures de la beta de Xailer 7 y dada la lógica falta de documentación, me encuentro con algunas dudas y problemas.

Pienso sustituir todos mis hilos por Futures para ganar en simplicidad de código y control pero....

1.- Si los futures se apilan para ser ejecutados en otro hilo de forma secuencial, como puedo saber
a) Si han finalizado todos, por que si intento salir de la aplicación antes de acabar estos, la aplicación da un lógico error
b) Se puede saber la lista de los que quedan por ejecutar? Se podrá asignar un nombre a cada uno para saber cual está haciendo y cuales quedan? He modificado el Sample Futures.Prg y cada Future me devuelve un :TaskCount() de 1, quizás deberia de instanciar para ello un solo Appdata:Future por aplicación y cargar a el todos los futures.

2.- Si hago un AWAIT INLINE {||SYNCHRO FUNCTION ¿se puede establecer un OnComplete? o no hay manera salvo haciendo un objeto instanciado con nombre como oFuture := TFuture():New()

3.- Además de OnComplete y OnError no veo otros eventos. No sería útil un evento OnStart por ejemplo, justo al contrario que OnComplete para inicializar objetos por ejemplo? No es necesario por que se puede hacer antes de llamar al Future pero...

4.- Si da un error la aplicación mientras está ejecutando un Future sale el error en pantalla pero se bloquea todo, lo he probado con el Sample Futures.Prg poniendo un error al final del tercero y poniendo en marcha los otros 2 pongo en marcha el tercero y zasca.

5.- Por último un error, he creado un Future para realizar las copias de seguridda de las BBDD de la aplicación al entrar (antes lo hacia con tThread) y ok funciona bien, es un proceso pesado y entre tanto puedo hacer otras cosas, esa es la idea. Pero resulta que tengo varios timer que refrescan diferentes cosas y si saltan algunos de ellos provocan errores curiosos, este es el primero y ando detras de otro que no se produce siempre.

______________________ Información detallada del error ______________________

Subsistema: WINOLE
Código de error: 1007
Estado: .F.
Descripción: No se puede hacer una llamada de salida desde la aplicación que está ejecutando una llamada sincrónica de entrada. (0x8001010D)
Operación: CONNECTSERVER
Argumentos:
Fichero: SWbemLocator
Código error SO: -2147352567

Pila de llamadas:
REALMEMORY (1436)
WIDGETSYSMETERREFRESH (1046)
(b)TFRMMAIN_FORMINITIALIZE (125)
TTIMER:ONTIMER (0)
(b)XTIMER (43)
TTIMER:WMTIMER (0)
WIN_OLEAUTO:RUN (0)
TSQLSTRUCTURE:DAILYBACKUP (3151)
(b)TFRMMAIN_PRUEBAASYNC (1600)
TFUTURE:RUNSYNCHRO (244)
(b)XFUTURE (51)
TFUTURE:WMXAILER (0)
RUNFORM (0)
TAPPLICATION:RUN (289)
MAIN (16)

Esta es la función que ejecuta, aunque me pasa en otras también, parace que no se puede acceder al API de Windows mientras está el future en marcha.

//Escanea la memoria del equipo y devuelve sus características en un array de 1 línea
//Devuelve tamaño_mem_real, tamaño_libre_mem_real, tamaño_mem_virtual, tamaño_libre_mem_virtual
Function RealMemory()

LOCAL oScriptObj, oWmiService, aRM := {}, oRM, aInfo:={}

oScriptObj = CREATEOBJECT( "wbemScripting.SwbemLocator" )
oWmiService = oScriptObj:ConnectServer() <<======Aqui se produce el error ¿?¿?¿?¿?¿??¿

aRM = oWmiService:ExecQuery("Select * from Win32_OperatingSystem")

for each oRM in aRM
AAdd(aInfo,{Val(oRM:TotalVisibleMemorySize),Val(oRM:FreePhysicalMemory) ,Val(oRM:TotalVirtualMemorySize),Val(oRM:FreeVirtualMemory)})
next

RETURN aInfo

Muchas gracias.

Re: Trabajado con Future's

Publicado: Lun Abr 20, 2020 5:01 pm
por ignacio
hola,
1.- Si los futures se apilan para ser ejecutados en otro hilo de forma secuencial, como puedo saber
a) Si han finalizado todos, por que si intento salir de la aplicación antes de acabar estos, la aplicación da un lógico error
Tienes el evento OnComplete y OnError en el futuro. Siempre puedes parar todo con el método TFuture:Stop()
b) Se puede saber la lista de los que quedan por ejecutar? Se podrá asignar un nombre a cada uno para saber cual está haciendo y cuales quedan? He modificado el Sample Futures.Prg y cada Future me devuelve un :TaskCount() de 1, quizás deberia de instanciar para ello un solo Appdata:Future por aplicación y cargar a el todos los futures.
He añadido el método CurrentTask(). Cada futuro puede tener múltiples tareas (tasks) pero se ejecutan una detrás de otra y no todas a la vez.

Además siempre se puede acceder a los 'taks' de un TFuture ya que es una instancia de la clase TFutureTask. Dejo el prototipado:

Código: Seleccionar todo

CLASS TFutureTask

PUBLIC:
   PROPERTY oParent     AS TFuture
   PROPERTY oError      READONLY
   PROPERTY nState      READONLY INIT ftUNCOMPLETED //      ftUNCOMPLETED        =>  0, ftCOMPLETEDWITHVALUE =>  1,  ftCOMPLETEDWITHERROR =>  2

   PROPERTY ReturnValue READONLY

   EVENT OnComplete( oSender, ReturnValue )

PUBLIC:
   METHOD New( oFuture, bBlock ) CONSTRUCTOR
   METHOD End()
   METHOD Run()

END CLASS
Por lo tanto sólo tienes que comprobar la propiedad nState de TFuture:aThreadTasks[..]

Código: Seleccionar todo

2.- Si hago un AWAIT INLINE {||SYNCHRO FUNCTION ¿se puede establecer un OnComplete? o no hay manera salvo haciendo un objeto instanciado con nombre como oFuture := TFuture():New()
Puedes usar la variable LOCAL 'ThisFuture', que siempre existe cuando pones la clásula ASYNC
4.- Si da un error la aplicación mientras está ejecutando un Future sale el error en pantalla pero se bloquea todo, lo he probado con el Sample Futures.Prg poniendo un error al final del tercero y poniendo en marcha los otros 2 pongo en marcha el tercero y zasca.
El primer código del ejemplo, en el método Btn1Click te muestra claramente cómo protegerte de los errores. Simplemente has de descomentar la línea que captura el error:

Código: Seleccionar todo

ThisFuture:OnError := {|| .T. } // Do not stop
Y la línea que lo provoca en el bucle:

Código: Seleccionar todo

nFor := nFor + "a"

Código: Seleccionar todo

5.- Por último un error, he creado un Future para realizar las copias de seguridda de las BBDD de la aplicación al entrar (antes lo hacia con tThread) y ok funciona bien, es un proceso pesado y entre tanto puedo hacer otras cosas, esa es la idea. Pero resulta que tengo varios timer que refrescan diferentes cosas y si saltan algunos de ellos provocan errores curiosos, este es el primero y ando detras de otro que no se produce siempre.
Esto tiene que quedar muy claro. Desde el futuro NO SE PUEDE ACCEDER AL INTERFACE DE USUARIO, y los TIMERS por supuesto tampoco. La solución es bien fácil, crea el timer en el Hilo principal.

Un saludo

Re: Trabajado con Future's

Publicado: Mar Abr 21, 2020 5:17 pm
por bingen
>>Esto tiene que quedar muy claro. Desde el futuro NO SE PUEDE ACCEDER AL INTERFACE DE USUARIO, y los TIMERS por supuesto tampoco. La solución es bien fácil, crea el timer en el Hilo principal.

Hola Ignacio, creo que no me expliqué bien. El timer está en el hilo principal, ya se que no puedo hacerlo desde el hilo, de hecho está funcionando con los tThread pero no con los Futures

Re: Trabajado con Future's

Publicado: Mar Abr 21, 2020 8:44 pm
por ignacio
Buenas,

Acabo de añadir en el ejemplo de futuros un nuevo control que incluirá Xailer 7 que incorpora un timer y no observo ningún problema. De hecho, el comportamiento de TFuture con los hilos es absolutamente transparente y sencillo que se resume en una sola línea de código:

hb_ThreadStart( nFlags, bCode )

No obstante, si consigues reproducirlo con el ejemplo de los Tfuture, te ruego me digas como. Gracias.

Un saludo


Re: Trabajado con Future's

Publicado: Mar Abr 28, 2020 6:20 pm
por bingen
Ok a ver si puedo reproducirlo, el timer llama al API de windows para preguntarle datos del sistema como la memoria y el procesador ocupados/disponibles