Etiqueta

12 de agosto de 2014

SQL en modo multitarea y multi-hilo (Parte 7 de 8)

Procesos “worker” huérfanos


Al lanzarse un $start(), el “Worker Delegate” se encargará de que se complete la tarea antes de invocar a los métodos del “Interface Object” $completed() o $cancelled(). Si se trata de un $run(), el “worker” será bloqueado para prevenir su cancelación, por lo que el método $completed() siempre será invocado.

Sin embargo, en caso de un $start(), el “Interface Object” puede quedar legítimamente desligado (huérfano) del “worker”, de lo contrario correría el riesgo de ser destruido antes de terminar la tarea que se le ha encargado ejecutar como subproceso. En éste momento, podemos decir que el subproceso no posee objeto alguno, se ha quedado huérfano y, por tanto, no es posible la invocación de los métodos $completed()/$cancelled(). En éste caso tanto los resultados como la información sobre posibles errores se descartarán.


 Proceso “Worker Delegate” huérfano. El “Interface Object” puede quedar desligado de su “Delegate”, y por lo tanto apuntar ahora hacia un nuevo “Worker Delegate”.

Tras la destrucción de un “Interface Object”, se transfiere la propiedad del “Worker Delegate” al “Thread Timer”. Un sólo objeto “Thread Timer” lleva acabo la supervisión de todos los objetos “Worker” de un determinado tipo, encargándose de eliminar los que hayan podido quedar huérfanos una vez concluidas sus tareas.

Un solo objeto “Thread Timer” supervisa todos los “Worker Delegates” de un determinado tipo. Un “Interface Object” sólo puede iniciar y recibir resultados de un único “Worker Delegate”, aunque pueden coexistir múltiples “Interface Objects”

1 de agosto de 2014

SQL en modo multitarea y multi-hilo (Parte 6 de 8)

Funcionamiento de los objetos “SQL worker”


El objeto “worker” puede ser representado mediante tres sub-objetos:

  • Interface Object
    Es el objeto no-visual estándar Omnis que proporciona los métodos y propiedades ya descritos anteriormente.

  • Worker Delegate Object
    Es el encargado de crear y ejecutar el subproceso en segundo plano. El “Worker Delegate” realiza el trabajo real del objeto “worker”, invocando al “Interface Object” cada vez que concluye.

  • Thread Timer Object
    Declarado estáticamente, cada “Worker Delegate” “suscribe” (por decirlo así) al ejecutarse ($start) un objeto “Timer Thread” (control multi-hilo). Todos los subprocesos poseen algún tipo particular de “Thread Timer”, el cual es responsable de que se vuelva a invocar su correspondiente “Interface Object”, tras concluir su ejecución.


Detrás de cada objeto “SQL Worker”, se esconde un “Worker Delegate” y un “Thread Timer”

30 de julio de 2014

SQL en modo multitarea y multi-hilo (Parte 5 de 8)

Ejecución de un “worker”


El método $start() causa que la tarea especificada para el “worker” sea ejecutada como un subproceso en segundo plano. Por lo tanto no se produce pausa o espera alguna, la aplicación continua con su ejecución. Observe el siguiente ejemplo, el cual presupone que disponemos de la variable “iWorkerObj” correctamente definida, tal y como se puede observar a continuación…

;; iWorkerObj es una variable de tipo Object definida bajo instancia
Calculate Params as row(
iSQLText,'192.168.0.10’,iUser,iPassword,iDBName)
Do Params.$redefine(query,hostname,username,password,database)
Do iWorkerObj.$init(Params)
Do iWorkerObj.$start() Returns #F

…el método $run() (proporcionado sólo con fines de depuración y pruebas) es análogo a $start(), pero no debe ser usado en modo de explotación, ya que el “worker” es ejecutado sobre un único hilo quedando bloqueado hasta que la tarea asignada concluye.

Una vez iniciado el objeto “worker” puede ser ejecutado varias veces si así se desea, siempre y cuando el objeto-sesión suministrado siga estando disponible o bien el grupo de sesiones (sesión-pool) disponga de una o más sesiones libres de uso y las credenciales de inicio de sesión sigan siendo válidas. Cualquiera de las variables vinculadas (bind) ya suministradas, serán reutilizadas cada vez que se ejecute el “worker”.

Si se produce un error durante la ejecución de un $init(), $start() o $run(), se enviará un mensaje de error mediante las propiedades del objeto denominadas $códigoerror y $erroreext.

Procesado de los resultados de un “worker”


Una vez concluida la tarea asignada al “worker”, se invocará uno de los dos métodos de devolución disponibles:

  • $completed()
    Este método es invocado junto con un parámetro de tipo “row” que contiene dos columnas: “Results”: con una lista de una sola columna con cero o más conjuntos de resultados SQL y “Errors”: una lista de dos columnas con los valores ErrorCode y ErrorMsg.

  • $cancelled()
    Este método es invocado (sin paso de parámetros) y se produce cuando el usuario ejecuta un $cancel() sobre el objeto “worker” mientras está en ejecución. Los resultados pendientes son descartados.

A menudo sucede que una misma librería contiene objetos “worker” de diferentes tipos, cada uno de ellos con una tarea específica (sentencia SQL) e iniciados en modo asíncrono. Por lo tanto, la responsabilidad sobre el tratamiento de los resultados depende del uso que demos a los métodos indicados anteriormente, es en ellos donde se podrá obtener información sobre los resultados y ponerlos a disposición de la aplicación. A modo de ejemplo, describimos un posible uso del método $completed().

Calculate List as pRow.Results.1.1 ;;extrae el primer conjunto de resultados
Calculate Errors as pRow.Errors ;;extrae la lista con los posibles errores
If Errors.$linecount()>0
    Do method reportError(Errors)
Else
    Do method updateWindow(List) ;; procesa resultados
End If
Calculate iThreadCount as $cinst.$threadCount ;; obtiene el número de hilos en proceso


En caso de que los resultados devueltos por $completed() deban ser mostrados sobre una ventana, necesitaremos dibujar de nuevo su instancia (la de la ventana) y si se trata de un “remote-form”, el cliente deberá contactarse de nuevo con el servidor para su actualización.

Estados de un “worker”


Para consultar el estado en que se pueda encontrar un objeto “SQL worker” deberemos hacer uso de su propiedad $state. Que podrá informar de los siguientes:

  • kWorkerStateCancelled – El “worker” ha sido cancelado.
  • kWorkerStateClear – El “worker” se ha iniciado.
  • kWorkerStateComplete – El “worker” ha concluido.
  • kWorkerStateError – Se ha producido un error (ver $errortext).
  • kWorkerStateRunning – El “worker” está actualmente en ejecución.

Ejemplo de uso:

If iWorkerObj.$state=kWorkerStateRunning&iWorkerObj.$waitforcomplete=kTrue
     Calculate iMesg as 'En ejecución (esperando su conclusión)'
     Quit method
End If