Este sitio web usa cookies de terceros para analizar el tráfico y personalizar los anuncios. Si no está de acuerdo, abandone el sitio y no siga navegando por él. ×


Curso de Pascal. Ampliación 4. Overlays.

Si trabajamos con MsDos y su famoso límite de 640 Kb, nos podemos encontrar con datos que ocupen más espacio que la memoria que tenemos disponible en nuestro ordenador.

Esto puede parecer un problema en un principio, pero una vez que se sabe cómo usar el acceso aleatorio a un fichero, la solución es fácil: leemos sólo los datos que necesitemos en cada momento.

Pero ¿qué ocurre si es nuestro programa el que necesita más memoria de la que tenemos?  ¿O simplemente si necesitamos más memoria libre?  Es habitual que, igual que ocurre con los datos, muchas partes de un programa se usan con poca frecuencia.  En cambio, en un programa no existe nada parecido al acceso aleatorio para tener en memoria sólo las rutinas que nos interesan en un momento concreto.

¿Nada?  Eso no es cierto del todo.  En Turbo Pascal tenemos una forma de conseguirlo: empleando overlays (En Free Pascal todo esto no es necesario: tenemos acceso a toda la memoria del sistema sin necesidad de estos "trucos", así que podemos manejar programas enormes de forma transparente).
 

La palabra "overlay" sale a querer decir algo parecido a "solapamiento". Y justo esa es la idea: al igual que hacíamos con los datos, podremos tener procedimientos o funciones que se "solapen" en memoria: en cada momento sólo tenemos uno de ellos en la memoria central (RAM), y cuando hace falta otro, éste sale y le deja su hueco en memoria.

Imaginemos que nuestro programa presenta un mensaje al principio de bienvenida (que sólo se emplea una vez en cada ejecución), otro de despedida al final (pasa lo mismo), y hay una rutina de ordenación de los datos, que sólo usamos una vez por semana.  Lo que nos interesa es, en vez de tener las 3 cosas en memoria, cargarlas sólo cuando las necesitemos.  Y aun hay más: como no tienen por qué ser simultáneas (no se ordena a la vez que se saluda, por ejemplo), podríamos liberar la memoria que ha usado una de ellas antes de cargar la otra.

Eso es lo que nos permite hacer el sistema de "overlays", que Turbo Pascal incorpora como estándar.
 

Ahora que vamos sabiendo por donde van los tiros, vamos a empezar a aplicarlo.

El programa debe empezar por incluir la unidad Overlay:


uses overlay, ... 

También debemos incluir las unidades que queremos solapar:


uses overlay, crt, dos, miUnit1, miUnit2 ...

Ahora tenemos que emplear 3 directivas de compilación:
 


Con todo esto, nuestro programa estaría quedando:
 


{$F+,O+}
program PruebaOverlays;

uses overlay, crt, dos, miUnit1, miUnit2;

{$O miUnit1}
{$O miUnit2}

begin
    [...] 

¿Más cosas?  Apenas un par de ellas.  Ya en el cuerpo del programa, usamos OvrInit para inicializar el sistema de overlays e indicar a nuestra aplicación en qué fichero se encuentran éstos:


OvrInit ( 'MIPROG.OVR' );

Ahora podemos comprobar que todo ha ido bien, mirando el valor de OvrResult.  Este será 0 si no ha habido problemas, o un número distinto si no ha podido inicializar todo correctamente.

Hay definidas unas constantes simbólicas para simplificarnos esas comparaciones:


     ovrOk          =  0;   { Todo correcto }
     ovrError       = -1;   { Error del manejador de overlays;
                              normalmente será que no hemos creado bien
                              los overlays }
     ovrNotFound    = -2;   { Fichero de overlays no encontrado. No
                              ocurrirá al compilar, pero puede pasar
                              después, si no distribuimos el .OVR junto
                              al .EXE }
     ovrNoMemory    = -3;   { No hay memoria suficiente para la zona de
                              solapamiento }
     ovrIOError     = -4;   { Error de E/S con el fichero OVR }
     ovrNoEMSDriver = -5;   { No existe memoria EMS (expandida) }
     ovrNoEMSMemory = -6;   { No hay suficiente memoria EMS } 

¿Por qué habla por ahí de EMS?  Pues porque podemos decirle además al compilador que queremos que nuestro programa intente cargar los overlays en memoria expandida (EMS).  Si lo consigue, será más rápido leer los procedimientos desde ahí que desde el disco.  Si no lo consigue, tampoco hay problema, porque entonces trabajaría con el disco como si nada.

¿Y cómo le pedimos que lo intente cargar en EMS?  Pues simplemente escribiendo


OvrInitEMS;

La última consideración, pero no menos importante, es que para que todo esto funcione debemos compilar a disco.

¿Las unidades a solapar?  Son unidades normales y corrientes, en las que debemos indicar al principio {$F+,O+}

Vamos ya a ver un ejemplo de cómo se aplica todo esto: El programa principal sería

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Programa que usa      }
 {    Overlays              }
 {    MIOVR.PAS             }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Turbo Pascal 7.0    }
 {--------------------------}

 {$F+,O+}                      { Necesario }

 program MiOvr;

 uses
   Overlay, Crt,               { Unidades que empleamos }
   MiUnit1, MiUnit2;

 {$O MiUnit1}                  { Indicamos cuales queremos solapar }
 {$O MiUnit2}

 var
   tecla: char;

 begin
   ClrScr;
   OvrInit('MIOVR.OVR');       { Inicializar y reservar memoria }
   {OvrInitEMS;}
   if OvrResult <> 0 then      { Si hay algún error }
   begin
     WriteLn('Error en el sistema de overlays: ', OvrResult);
     Halt(1);
   end;
   repeat
     Proc1;                    { De la unidad 1 }
     Proc2;                    { De la unidad 2 }
     WriteLn;                  { Para que se lea mejor }
     delay(50);                { Y esperamos un poco }
   until KeyPressed;           { Así hasta que se pulse una tecla }
   tecla := ReadKey;           { Absorbemos la tecla pulsada }
 end. 

 


La primera unidad podría ser:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Primera unidad sola-  }
 {    para para MIOVR       }
 {    MIUNIT1.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Turbo Pascal 7.0    }
 {--------------------------}

 {$O+,F+}

 unit MiUnit1;

 interface

 procedure Proc1;
 

 implementation

 procedure Proc1;
 begin
   Writeln('Estoy en la primera unidad.');
 end;

 end. 

 

Y la segunda unidad:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Segunda unidad sola-  }
 {    para para MIOVR       }
 {    MIUNIT2.PAS           }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Turbo Pascal 7.0    }
 {--------------------------}

 {$O+,F+}

 unit MiUnit2;

 interface

 procedure Proc2;
 

 implementation

 procedure Proc2;
 begin
   Writeln('Estoy en la segunda unidad.');
 end;

 end.
 

 

Y si queremos emplear EMS, las unidades no cambian, y el programa principal podría ser:

 {--------------------------}
 {  Ejemplo en Pascal:      }
 {                          }
 {    Programa que usa      }
 {    Overlays y los guarda }
 {    en memoria EMS        }
 {    MIOVR2.PAS            }
 {                          }
 {  Este fuente procede de  }
 {  CUPAS, curso de Pascal  }
 {  por Nacho Cabanes       }
 {                          }
 {  Comprobado con:         }
 {    - Turbo Pascal 7.0    }
 {--------------------------}

 {$F+,O+}                      { Necesario }

 program MiOvr2;

 uses
   Overlay, Crt,               { Unidades que empleamos }
   MiUnit1, MiUnit2;

 {$O MiUnit1}                  { Indicamos cuales queremos solapar }
 {$O MiUnit2}

 var
   tecla: char;

 begin
   ClrScr;
   OvrInit('MIOVR.OVR');       { Inicializar y reservar memoria }
   OvrInitEMS;
   if (OvrResult = -5) or
     (OvrResult = -6) then     { Si hay problemas con la EMS }
   begin
     WriteLn('Error con la EMS.  Usando el disco...');
     Delay(1000);              { Avisamos y seguimos }
   end
   else
     if OvrResult <> 0 then      { Si hay algún error "serio" }
     begin
       WriteLn('Error en el sistema de overlays: ', OvrResult);
       Halt(1);
     end;
   repeat
     Proc1;                    { De la unidad 1 }
     Proc2;                    { De la unidad 2 }
     WriteLn;                  { Para que se lea mejor }
     delay(50);                { Y esperamos un poco }
   until KeyPressed;           { Así hasta que se pulse una tecla }
   tecla := ReadKey;           { Absorbemos la tecla pulsada }
 end. 

Como último comentario: al buffer de solapamiento se le asigna el tamaño más pequeño que haga falta, y que coincide con el Overlay más grande. Si queremos un buffer mayor, para intentar que el programa haga menos lecturas de disco y sea más rápido, podemos leer el tamaño actual del buffer con OvrGetBuf, y cambiarlo con OvrSetBuf.