Etiqueta

10 de septiembre de 2014

Uso de las variables "Object Reference"

Un problema


A medida que nos hemos ido familiarizando con el uso de objetos y especialmente cuando los hacemos disponibles por medio de variables de instancia, empezamos a tropezar con situaciones en las que nos gustaría acceder a un objeto (variable) desde fuera de su ámbito normal. Por ejemplo, podríamos querer pasar un objeto que contiene datos importantes desde una instancia-ventana a una instancia-informe o incluso a otra instancia-ventana diferente. Pero si pasamos la variable de objeto como parámetro, obtendremos una copia nueva e independiente de ese mismo objeto y puesto que se trata de un parámetro, solo alcanzable desde un ambito local. Si posteriormente copiamos el objeto sobre una nueva variable de instancia, con el fin de hacerlo disponible en ese ambito, estaremos duplicando de nuevo el objeto original, al final podría resultar que terminásemos con un sin fin de copias del mismo objeto.

Naturalmente, cualquier cambio que posteriormente realicemos sobre estas copias no será reflejado en el objeto original. Podemos decir que las copias pasan a tener vida propia tan pronto como son creadas. Por supuesto podemos compartir un objeto común mediante (por ejemplo) el uso de una variable de clase, ya que estaría disponible para todas las instancias generadas a partir de esa misma clase, por ejemplo, entre las varias instancias de la misma clase-ventana. Pero en ese caso ya no tendríamos el objeto a nivel de instancia, sino que afectaría a todas las diferentes instancias de la clase.

Una solución


Las variables "Object Reference" nos permiten crear un puntero hacia un objeto, eliminando la necesidad de realizar una nueva copia del mismo. Esto resulta en un uso más eficiente de los recursos de memoria RAM en nuestra aplicación y al mismo tiempo dotamos de una mayor coherencia a las acciones requeridas para con ese Objeto. Como veremos, también disponemos de algunas "utilidades" con las que realizar un seguimiento de las referencias o punteros en uso.

Pero no podemos simplemente crear referencias para las variables-objeto que tengamos creadas. Debemos tener en cuenta, que las variables-objeto son en realidad contenedores de los objetos instanciados y las "Object Reference" generan punteros hacia dichas instancias por lo que sólo podemos usarlos con instancias de objetos que han sido generadas de un modo algo diferente al habitual. Puesto que no se ha acuñado término alguno para éste tipo de instancias, las llamaremos "referenciables" o también "instancias refrenciadas".

 

Creación de un "Object Reference"


Ya sabemos que podemos generar dinámicamente instancias de un objeto mediante su método $new(), el valor devuelto por éste, es la instancia propiamente dicha. Podemos hacer esto mediante el comando "Do" o mediante "Calculate", tal como se observa en el siguiente ejemplo:

Do $objects.demoObject.$new(5) Returns demoObj
Calculate demoObj as $objects.demoObject.$new(5)

El "5" en estos ejemplos es un valor enviado como parámetro al método $construct de la instancia y que (como sabemos) es ejecutado automáticamente en el momento de su creación.

Por supuesto ésta no es la única forma de generar una instancia, (por ejemplo) podríamos hacerlo mediante definir una variable objeto (en el panel de definición de variables) y asignarle un valor como sub-tipo desde una clase en nuestra librería u otras opciones similares, pero en éste artículo optamos por la creación dinámica de instancias, a fin de que pueda observarse con mayor facilidad los elementos que son objeto de discusión.

Esencialmente, las variables "Object Reference" son asignadas bajo el mismo criterio o modo que las variables "Object". De hecho, desde la versión 4.0, existe en Omnis Studio un método creado específicamente con este propósito. El método $newref(), su uso:

Do $objects.demoObject.$newref(5) Returns objref
Calculate objref as $objects.demoObject.$new(5)

Al ejecutarse, este método se crean ambas cosas, es decir, un objeto y una referencia, se crea una nueva instancia de ese objeto y un valor de referencia que apunta hacia esa misma instancia. La instancia es creada directamente a partir de la clase, Omnis añadirá un carácter de subrayado y un número entero al componer el nombre de la instancia con el fin de que sea único y al mismo tiempo guarda un puntero hacia esa misma instancia, en la variable de tipo "Object Reference" especificada.

Ambos tipos de variables (Object y Object Reference) son iguales desde el punto de vista operacional, pero con una sutil y gran diferencia...

Cuando hacemos uso de "Object reference" para crear instancias, el Objeto "referenciable" (término con el que hemos bautizado a las instancias referenciadas), es decir la instancia continuará existiendo aún después de que su puntero o variable "Object reference" haya sido destruida. De hecho, perdemos contacto con dicha instancia (excepto si es a través del grupo $inst) a menos que nos aseguremos de tenerlo a buen recaudo.

Paso de "Object References"


Si queremos pasar un valor "Object reference" como parámetro, tendremos simplemente que especificar el nombre de la variable de tipo "Object reference" (que contiene el valor) como parámetro durante la llamada al método, igual que lo haríamos con cualquier otro. La variable-parámetro en el método de recepción, también deberá ser de tipo "Object reference". En su ejecución, dicha variable-parámetro constituirá otro punto de acceso a la misma instancia.

Si lo deseamos, también podemos duplicar la referencia sobre otra variable mediante el comando "Calculate", el método "$assign()" o bien mediante asignar su valor de retorno, a continuación mostramos los tres posibles modos:

Calculate dataObjRef2 as dataObjRef1
Do dataObjRef1 Returns dataObjRef2
Do dataObjRef2.$assign(dataObjRef1)

Note que (en éste caso) no podemos hacer uso del comando "Set reference", ya que sólo funciona con variables de tipo "Item reference" y evidentemente las "Object reference" no son "Item reference". La transmisión de valores deberá hacerse entre variables del mismo tipo.

Dado que diferentes celdillas de una variable de tipo lista, también se comportan como variables en si mismas, podemos hacer uso de las mismas técnicas para la asignación de valores, así un "Object reference", puede ser guardado en una celdilla. Por ejemplo, si se definió "listVar" para incluir una columna de tipo "Object reference" con el nombre "dataObjRef2" y queremos copiar la referencia de "dataObjRef1" sobre la celda de la línea 3, usaríamos:

Calculate listVar.3.dataObjRef2 as dataObjRef1

Tanto "dataObjRef1", como la celda en la lista, apuntan ahora a la misma instancia.

Un mayor poder, conlleva una mayor responsabilidad


Si usamos esta herramienta, deberemos también asumir la responsabilidad de mantener aseados nuestros propios líos (La versión 6.1 de Omnis permitirá otorgar cierto automatismo a ésta tarea). En su uso habitual con una variable de tipo "Object", la instancia correspondiente es destruida automáticamente tras eliminarse su variable, lo cual ocurre cuando el elemento (método, instancia o tarea) que lo la contiene se cierra, en estos casos, Omnis Studio gestiona esta tarea de limpieza por nosotros.

Pero cuando usamos una variable "Object reference" y luego la destruimos, la instancia del objeto referenciado al que señalaba continúa existiendo. Sólo se destruye su referencia. La instancia del objeto sigue viva en algún lugar de la memoria RAM, ya que podrían existir otras variables de tipo "Object reference" que aún la necesiten. Nos corresponde a nosotros escribir el código necesario para destruir la instancia y mantener limpio el espacio RAM. El único momento en que la instancia de un objeto referenciado es destruido automáticamente, es cuando a su vez la tarea que lo contiene es destruida o bien al salir de Omnis Studio.

Entonces, ¿cómo eliminar las instancias "huérfanas"? Podremos hacerlo mediante el método $deleteref(). Este método nos permitirá eliminar la instancia del objeto al que apunta la variable "Object reference" indicada. Su ejecución causará la llamada del método $destruct de la instancia, como parte del proceso. Exactamente del mismo modo que sucede con cualquier otra instancia.

No podemos aplicar el método $deleteref() directamente sobre la instancia, pero si disponemos de un modo para localizar las instancias-referenciadas, se trata del método $listrefs(). (Se ha de tener en cuenta que mediante este método obtendremos todas instancias-referenciadas, sea que estén "huérfanas" o no) Podremos usarlo en cualquier lugar de nuestra aplicación. Se nos devolverá una lista de todas las instancias-referenciadas, según el nivel del árbol de notación en que lo apliquemos, si es $root, será a nivel global, es decir todas las existentes en nuestra aplicación.

La lista constará de una sola columna con los valores "Object reference", sobre las que se podrá aplicar el método $deleteref(), para hacerlo sobre todo el conjunto, usaríamos el método $sendall(). El Manual de programación Omnis en castellano, proporciona algunos ejemplos útiles sobre su uso.

Si lo que quiséramos fuera hacer una copia, disponemos del método $copyref(). En éste caso, el valor de retorno del método será un nuevo "Object reference", al igual que ocurría al aplicar el método $newref() y al igual que éste, $copyref() generará una nueva instancia del objeto referenciado, se trata (por tanto) de un duplicado exacto (a excepción de su nombre, por supuesto) de la instancia a la que apunta las variable "Object reference" original.

En el ejemplo siguiente usamos "dataObjRef1" para crear un duplicado de la instancia a la que hace referencia, guardando en "dataObjRef2" un puntero hacia la recién creada:

Calculate dataObjRef2 as dataObjRef1.$copyref()

También podemos utilizar el comando "Do", con o sin el método "$assign()", para realizar la misma tarea. Se ha de tener en cuenta que las instancias creadas son completamente independientes entre sí, pero estará bien, si eso es lo que queremos. El posterior uso de "$listrefs()" sobre la clase de objeto original, mostraría (al menos) dos instancias referenciadas en la lista.

Pero ¿qué pasa si por error destruimos una instancia, cuando resulta que aún existía una variable "Object reference" apuntando hacia ella? ¿Cómo podemos saber si el "Object reference" que deseamos utilizar sigue siendo válido? No nos alarmemos, el método "$validref()", acude en nuestra ayuda, nos permite probar si la referencia es aún utilizable. Este método devuelve un valor booleano, si es kTrue significará que la referencia es válida.

Aunque bien podría considerarse una exageración utilizar este método antes de realizar cualquier acción que implique el uso de una variable "Object reference", habrá ocasiones en las que sea razonable realizar una comprobación de este tipo. Considere (por ejemplo) el caso en que haya recibido la referencia desde una fuente externa, si es así, es muy posible que deseemos comprobar si aún sigue siendo válida, supongamos que hemos programado en una ventana la ejecución del método "$deleteref()" en su "$destruct", cuando es el caso que existen otras ventanas aún abiertas que requieren de su uso, ocurriría que la referencia pasada a esta segunda ventana no sería válida.

Llegados a éste punto, les propongo desde "Aula Omnis" un ejercicio sencillo para demostrar que una instancia referenciable puede continuar vinculada. Estos son los pasos:

  • En primer lugar, ejecutamos el método "$newref()" dentro de una tarea para generar una instancia referenciable y capturar su referencia en una variable de tipo "Object reference".
  • A continuación, pasamos el "Object reference" a otra tarea y la testamos ($validref) para asegurarnos de que nos estamos comunicando con la instancia original.
  • Luego destruimos la primera tarea, que a su vez destruirá la instancia referenciable que hemos generado desde dentro de ella.
  • Desde la tarea que nos queda, testemos de nuevo la variable "Object reference" con el método "$validref()". No será válida, lo que significa que la instancia original fue destruida.

Si lo desea también podría construir una lista de todas las instancias mediante "$listrefs()" antes y después de la destrucción de la tarea.

(basado de un articulo de David Swain)

5 de septiembre de 2014

Uso de $ref y $sendallref

Uso de $ref como sufijo


El uso de $ref como sufijo (es decir situado al final de la notación) es sin duda el modo más simple de uso. En éstos casos, $ref devuelve una referencia al elemento de notación al que se aplica. Puede resultar útil si (por ejemplo) lo que deseamos es pasar la referencia del elemento como parámetro durante la llamada a un método o para simplemente guardarla en una variable de tipo "Item reference" mediante el comando "Set reference". Naturalmente el uso de $ref no es estrictamente necesario para éste tipo de operaciones, pero hará que la notación se vea más completa y "correcta". De modo que aprovechamos la redacción de éste artículo para sugerirle que se habitue en su uso.

A modo de ejemplo, supongamos que queremos guardar en una variable de tipo "Item reference" la referencia a un campo de tipo lista, situado en la instancia actual de una ventana. Podríamos hacer lo siguiente:

Set reference listFieldRef to $cinst.$objs.listField.$ref

Usado de éste modo, $ref funciona como si se tratase de una propiedad del elemento al que se aplica. También actúa un poco a modo de método, ya que devuelve su referencia. De hecho, si prefiere pensar en ello como si de un método se tratase, puede hacer uso de $ref con paréntesis, (como lo haríamos con un método real) del modo siguiente:

notacion.$ref()

Podemos concluir que el uso de $ref como sufijo, se posiciona en algún lugar entre propiedad y método. Pero en éste artículo queremos centrarnos en otros modos de uso mucho más interesantes...

Uso de $ref como prefijo


Cuando usamos $ref como prefijo (es decir situado al principio de la notación) y a su vez dentro del parámetro en un método, $ref hará referencia al elemento en el que se aplica dicho método, es como un puntero reflexivo. Nótese la sutil diferencia entre éste modo y su uso como sufijo. En este caso, $ref usado como parámetro es aplicado a sí mismo. Si bien esto puede parecer un poco confuso al principio, es una característica ¡muy potente!

Para entenderlo mejor, pensemos en el método $assign(), que usamos habitualmente para asignar un valor a cualquier variable (incluidas las propiedades de los elementos). Podríamos hacer uso de $ref como parámetro del mismo, de éste modo actuará como referencia a la variable que precisamente va a recibir la asignación del valor. Por ejemplo, si tenemos una variable numérica llamada numberVar1 y deseamos incrementar su valor en 5, podríamos escribir...

Do numberVar1.$assign($ref+5)

...en lugar de...

Do numberVar1.$assign(numberVar1+5)

En ambos casos obtendremos el mismo resultado.

También podremos usar $ref de esta manera, dentro de las posibles funciones incluidas en el parámetro del método $assign(). Considere el caso en el que deseamos concatenar caracteres adicionales al contenido actual de una variable de tipo texto:

Do stringVar.$assign(con('Esta variable contenía "',$ref,'" antes de hacer clic en el botón.'))

Note como su inclusión en la función con() no interfiere en el uso de $ref.

Un ejemplo más. Supongamos que en el método perteneciente a un campo, queremos incrementar el valor de su variable asociada en 5 unidades. Queremos escribir el código de forma genérica para que podamos copiarlo y pegarlo en cualquier otro campo. La línea de código necesaria sería:

Do [$cfield.$dataname].$assign($ref+5)

Sea cual sea el nombre de la variable asociada, vera incrementado su valor por 5 unidades.

Pero aún existe otro modo más interesante de usar $ref...

Uso de $ref con métodos grupales


La notación $ref tiene un significado ligeramente diferente cuando es usado como prefijo de una notación, incluida a su vez dentro de un parámetro en un método grupal. Al usarse de éste modo $ref hará referencia al miembro actual del grupo, según cada una de sus iteraciones.

Supongamos que queremos construir una lista con las instancias de ventana abiertas. Queremos incluir en ella su nombre, su título y el nombre de cada instancia. Haremos uso del método $makelist() aplicándolo sobre el grupo $iwindows. Para obtener los valores de dichas propiedades sobre la lista resultante, haremos uso de $ref del modo siguiente:

$iwindows.$makelist($ref.$name,$ref.$title,$ref.$class().$name)

Nótese que debemos resolver (mediante el uso de los paréntesis) el $class del tercer parámetro. Si no lo hiciéramos, nos devolvería "$class".

En su ejecución, $ref ira referenciando a cada uno de los miembros del grupo $iwindows. Nosotros sólo tendremos que añadir a $ref la propiedad, el método o la variable que deseemos.

Llegados a éste punto, debemos tener en cuenta que no todos los métodos grupales pueden hacer uso de $ref, sino sólo aquellos usables de forma iterativa. Esto es debido a que algunos métodos de grupo, tales como $next(), ni siquiera admiten parámetros. Otros, como $remove(), requieren del uso de un puntero o referencia hacia un miembro específico del grupo y por tanto no puede ser aplicado de forma iterativa. Para cada método grupal, disponemos a su vez de cuatro métodos que se ajustan a estos criterios: $makelist(), $appendlist(), $insertlist() y $sendall(). Los tres primeros son simples variaciones sobre un mismo tema, por lo que en realidad sólo existen dos (el que permite obtener la lista de los miembros del grupo y el que permite el envío de mensajes a cada uno de ellos) mediante los cuales hacer uso de $ref.

Presupongo que la mayoría de los desarrolladores en Omnis Studio hacemos uso frecuente del método $sendall(). Es el método utilizado para enviar mensajes a los miembros de un grupo y que (como sabemos) dispone de dos parámetros, el primero conforma el propio mensaje y el segundo es una expresión de búsqueda que permite determinar el alcance del mensaje, es decir, permite determinar que miembros concretos del grupo podrán atender el mensaje. El segundo parámetro es opcional, si es omitido, todos los miembros atenderán el mensaje.

$ref puede ser usado con cualquiera de los parámetros. Observe el siguiente ejemplo:

Do $iwindows.$sendall($ref.$close(),$ref.$style=kTitle)

Aquí le estamos diciendo a todas las instancias de ventana que se cierren, pero con la condición de que se trate de ventanas de tipo "title". Hemos usado un método ($close()) y una propiedad ($style) con $ref. Por supuesto, cualquiera de estos parámetros podría contener construcciones más complejas. En éste artículo decubriremos algunas cuestiones a tener en cuanta cuando hacemos uso de $ref de modo aún más complejo...

Uso de $ref con métodos de listas


Doy por supuesto que usted ya conoce el uso de las variables de tipo lista, si es así, seguramente también sabrá que una variable de tipo lista también actúa como si se tratase de un método grupal o notación de grupo, donde las líneas contenidas serían los diferentes elementos del grupo. Sabiendo esto, se deduce que cualquier método aplicado a una variable de tipo lista, es realmente un método de grupo, al cual se le pueden aplicar métodos exclusivos de éste tipo de variables como $search() y $sort(), por tratarse en realidad de variables de tipo lista.

El primer parámetro del método para listas $search() contiene la especificación de búsqueda, es decir, la expresión utilizada para seleccionar las líneas de la lista. (por ahora haremos caso omiso de los otros cuatro parámetros de este método) $ref podrá ser usado para referenciar a la línea actual de esa lista, como parte del método que analiza las líneas de la lista en busca de las que cumplan con los criterios establecidos. Normalmente necesitaremos añadir a $ref el nombre de una columna de la lista, ya que muy probablemente queremos localizar líneas en base al contenido de sus celdas. Por ejemplo, si queremos seleccionar todas las líneas en las que el valor de la columna "quantitysold" sea mayor que 5, tendremos que utilizar:

Do listVar.$search($ref.quantitysold>5)

También pudiera suceder que deseáramos seleccionar las líneas en función de los valores contenidos en diferentes columnas de esa misma línea. Por ejemplo, si queremos seleccionar todas las líneas donde "quantityshipped" es inferior a "quantitysold", podríamos utilizar:

Do listVar.$search($ref.quantityshipped<$ref.quantitysold)

Esta comparación se va realizando línea a línea. El uso de $ref es seguramente la forma más sencilla de garantizar esto.

Con el método $sort() normalmente usaremos un par de parámetros. El primero para el criterio de clasificación y el segundo para el indicador boleano de dirección de ordenación (kTrue si es descendente, por defecto es kFalse - ascendente). Recordemos que también podemos hacer uso de $ref dentro de las funciones, por ejemplo:

Do listVar.$sort(upp($ref.lastname),kFalse,upp($ref.firstname),kFalse)

Por supuesto el método $sendall() también puede ser usado con una variable de tipo lista. En éstos casos, $ref se refiere a cada línea de la lista en su turno. Así que sólo podemos anexar propiedades, métodos y nombres de celdas, en correspondencia con una línea de la lista, es decir en el ambito de una línea simple. El primer parámetro de $sendall() contiene la expresión que será evaluada para cada línea. Este parámetro es necesario (ya que de no proporcionarse haría del método algo inútil). El segundo parámetro es el que contendrá los criterios de búsqueda, que deberán cumplir las líneas sobre las que actuará el primer parámetro, si se omitiese se aplicará a toda la lista. $ref puede utilizarse en  cualquiera de los parámetros.

Por ejemplo, si quisiéramos ejecutar un proceso incluido en la instancia de la ventana actual, pasándole como parámetros información obtenida de cada una de las líneas de la lista, según cumplan con los criterios establecidos, usaríamos lo siguiente:

Do listVar.$sendall($cinst.$processlineinfo($ref.C1),$ref.C2>20)

Este comando pasa el valor de la columna 1 al método $processlineinfo() ubicado en la instancia de la ventana, ejecutándose para cada línea cuyo valor en la columna 2 sea mayor de 20. Si bien se trata de un ejemplo sencillo, observe como $ref nos permitió pasar el valor como parámetro en la llamada al método incluido dentro del primer parámetro de $sendall(). Los parámetros para $sendall() pueden llegar a ser bastante complejos, en la medida que nos familiarizamos con su uso. De momento ya hemos aprendido a ejecutar métodos incluidos. El uso de $ref se complica un poco cuando lo usamos de forma anidada, es decir cuando incluimos métodos dentro de métodos.

Uso de $ref con métodos anidados


Si bien el uso de $ref con métodos anidados puede darse en otras estructuras, lo más común es que lo encontremos asociado al método $sendall() y por tanto, es bajo su uso que queremos llamar la atención al problema que resolvemos a continuación. Las expresiones dentro de los parámetros de $sendall() pueden realmente llegar a ser muy complejas, e implicar el uso de métodos anidados, de hasta un máximo de cinco niveles de profundidad. ¡Piense en uno o más métodos $sendall() anidados dentro de otros! Esto crea un pequeño problema (aunque no sin solución) con el uso de $ref en los niveles más profundos, sobre todo si lo que queremos en que se haga referencia al elemento más exterior y no al correspondiente a su nivel. Por definición, cualquier método que hace uso de $ref lo hace según el nivel en el que se encuentre. No obstante, decir que Omnis Studio no proporcionaba una alternativa para solventar éste problema, hasta la versión 4.2, hasta entonces no hubo otro remedio que escribir notaciones más específicas o simples.

Considere este caso: Queremos pasar el valor contenido en una determinada columna y para cada línea de una lista utilizando $sendall(). Para nuestro primer ejemplo, supongamos que simplemente queremos cambiar el valor de una columna booleana, haríamos lo siguiente:

Do listVar.$sendall($ref.booleanColumn.$assign(not($ref)))

Observe que en el primer uso de $ref hace referencia a la línea en curso, pero en su segundo uso (anidado dentro del método $assign) hace referencia a la celda específica sobre la que se va aplicando el método $assign en cada iteración. Esto causa que cambie el significado de $ref. En nuestro primer ejemplo, el cambio resulta beneficioso, ya que realmente queremos hacer uso del valor actual de la celda para simplemente asignarle un nuevo valor. Pero... ¿y si lo que quisiéramos fuera asignar un nuevo valor a la celda, en función de lo contenido en otras de la misma línea? Observe el siguiente ejemplo:

Do listVar.$sendall($ref.sumColumn.$assign($ref.columnA+$ref.columnB)) 

Esto definitivamente no va a funcionar. La notación no es válida, a menos que "sumColumn" fuese en realidad una lista, una row u otro objeto que contuviese a su vez las variables "ColumnA" y "ColumnB", pero definitivamente no es ese nuestro caso. Claro que podríamos solucionarlo utilizando el nombre de la variable de lista en lugar de $ref. Pero lo que queremos es algo que nos funcione en todos los casos, sin tener que modificar su sintaxis.

Entonces... ¿qué podemos hacer?

Afortunadamente $sendallref acude a nuestro rescate.

La razón, es que $sendallref permite mantener la referencia al elemento actual durante la ejecución del bucle $sendall(), incluso cuando está dentro de un parámetro. Así que ahora podemos reformular el problema anterior del siguiente modo:

Do listVar.$sendall($ref.sumColumn.$assign($sendallref.columnA+$sendallref.columnB))

De éste modo conseguimos referenciar correctamente a las columnas dentro de la línea objetivo del método $assign(). Ocurriría exactamente lo mismo en situaciones similares a esta, cuando estemos usando $sendall() con otras notaciones grupales.

Tener en cuanta que $sendallref no es el sustituto definitivo de $ref, podemos seguir usando éste último para los casos más sencillos donde si es posible su uso, pero realmente podemos utilizar uno u otro indistintamente, la única diferencia es que requiere el triple de pulsaciones de teclado para escribirse. Aunque (si se me permite una licencia) me parecería coherente usar $sendallref, siempre que se use con $sendall.

(artículo original de David Swain)
 

14 de agosto de 2014

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

Eliminación de procesos en ejecución


Durante el tiempo que un “Interface Object” esté operativo será posible invocar sus métodos $init() y $start(), aún en el caso de que el “Worker Object” esté ejecutando una tarea anterior. En este caso, será su propiedad $waitforcomplete quien determine si el proceso en ejecución debe continuar hasta completarse o no, informando al “Interface Object” de su finalización.

Si $waitforcomplete es kFalse, el proceso en ejecución será desligado del “Interface Object”, tal y como si estuviera a punto de quedar huérfano, sin embargo, lo que sucede, es que se crea un nuevo objeto “Worker Delegate” que será utilizado para la ejecución de la nueva tarea, con la capacidad necesaria para informar  al “Interface Object” de su finalización.

Si $waitforcomplete es kTrue, El “Worker Main” o objeto “worker” en uso, devolverá un error al “Interface Object” ante cualquier intento de volver a utilizarlo, mientras sucede que aún está en ejecución su “Worker Delegate” correspondiente. En estos casos, los objetos “worker” no pueden ser re-utilizados hasta que se produce el correspondiente $completed()/$cancelled(), será su propiedad $state quién podrá indicar su finalización.

Para entender mejor su funcionamiento, podríamos decir que un objeto “worker” con su propiedad $waitforcomplete fijada como kFalse, se convierte a todos los efectos en una especie de “dispara y olvídate”, lo cual causa que, por ejemplo, una sucesión de sentencias INSERT, UPDATE o DELETE sean remitidas al servidor de forma continua y en hilos de ejecución separados desde un único objeto.


Cancelación de procesos huérfanos


Si no se indica lo contrario (por defecto), a los subprocesos que han quedado huérfanos se les permite llegar hasta su terminación. No obstante, en algunos casos puede ser preferible emitir una solicitud para su cancelación, ($cancelled) especialmente si se estaba ejecutando una sentencia SELECT, ya que sabemos que no podremos recuperar su resultado por haber quedado desligado de su “Interface Object”. Esto se logra mediante fijar la propiedad $cancelifrunning a kTrue, antes de que el objeto “worker” sea reutilizado o destruido.

La propiedad $cancelifrunning es por defecto kFalse, por lo tanto, los subprocesos que han quedado huérfanos son ejecutados por completo antes de desecharse sus resultados y ser destruidos por el objeto “Thread Timer”.