lunes, noviembre 23, 2009

Harbour VS xHarbour, Las diferencias verdaderas (Parte 8)

Variables locales separadas (detached locals) y referencias.

Cuando se usan variables locales en bloques de código, existe la posibilidad de que dichos bloques de cóidgo existan después de salir de la función donde han sido creados. Esto es un problema potencial muy serio el cual tiene que ser resuelto para evitar corrupción de la estructura de la máquina virtual.

En Clipper, Harbour y xHarbour, se utiliza un mecanismo especial en dicha situación. Las variables locales son "separadas" del stack de la máquina virtual de tal forma que se puede acceder a ellas despues de dejar la función donde fueron declaradas como locales, por ejemplo:
      proc make_cb()
local n := 123
return {|| ++n }
A esas variables se les llama "locales separadas" (detached locals).

Aquí hay 2 importantes diferencias entre Clipper y [x]Harbour. En Clipper las varaibles son separadas cuando se sale de la función (return) y no tiene manera de saber cuales variables locales fueron usadas por un bloque de código, de tal forma que TODAS las variables locales se separan del stack de la máquina virtual. Es muy impornte saber que esto es el origen de varios problemas serios de memoria en sistemas operativos como DOS.

Este código ilustra el comportamiento:
     // linkee usando RTLINK y ejecuta con //e:0 //swapk:0
// repite una segunda vez con un parametro no vacío para la variable 'x'
#define N_LOOPS 15
#xcommand FREE MEMORY => ? 'free memory: ' + ;
AllTrim( Str( Memory( 104 ) ) )
proc main( x )
local n, a
a := array( N_LOOPS )
FREE MEMORY
for n := 1 to N_LOOPS
a[n] := f( x )
FREE MEMORY
next
return
func f(x)
local cb, tmp, ref
tmp := space( 60000 )
if empty( x )
cb := {|| .t. }
else
cb := {|| ref }
endif
return cb

Si ejecutas el programa anterior sin parametros vacíos, entonces la variable 'tmp' se separa con el bloque de código que utiliza la variable 'ref' y no se libera mientras el bloque de código sea accesible. Esto significa que en unas pocas iteraciones se consume toda la memoria y el programa falla. Los programadores de Clipper deben saber esto y ser cuidados con el uso de locales separadas y si es necesario inicializar explicitamente otras variables locales antes de retornar de la función asignandoles un valor de NIL.

En Harbour y xHarbour solo las variables explícitamente usadas en bloques de código son separadas y la separación ocurre cuando el bloque de código es creado y las variables locales originales son reemplazadas por "referencias". Esto es posible porque Harbour y xHarbour soportan cadenas de referencias multinivel, esto funciona correctamente también para parámetros locales pasados por referencia desde funciones padres.

Clipper solo soporta un nivel de referencia lo que crea una segunda e importante diferencia:

Cuando Clipper separa un conjunto de parámetros locales, tiene entonces que quitar toda las referencias existentes rompiéndolas. Este código lo ilustra:
      proc main()
local cb, n := 100
mk_block( @cb, @n )
? "after detaching:"
? eval( cb ), n
return
proc mk_block( cb, n )
n := 100
cb := {|| ++n }
? "before detaching:"
? eval( cb ), n
return
El código anterior compilado con Clipper muestra

Antes de separar:
             101        101
Despues de separar:
             102        101
Así pues, después de separar las referencias a la variable 'n', esta referencia se rompe y los bloques de código acceden a su propia copia la varaible.

En Harbour funciona correctamente y los resultados son mostrados como debe ser:

Antes de separar:
             101        101
Después de separar :
             102        102
En xHarbour (por razones desconocidas por mí) ¡ el bug de Clipper se emula explícitamente !, aunque en su momento fue posible corregirlo porque xHarbour heredó de Harbour el mismo mecanismo de separación de referencias multinivel, así que, tanto los programadores de Clipper, como los programadores de xHarobur tienen que ser cuidadosos con la posiblidad de que existan referencias rotas debido a las locales separadas y añadir correcciones de ser necsario.

Continuará....

No hay comentarios.: