November 2008

Introducción a la programación multihilo

Antes de empezar

En este articulo no hay ni una sola linea de código y no esta orientado a enseñar los entresijos especificos de la programación multihilo en este o aquel lenguaje sino a dar una pequeña introducción, centrandose fundamentalmente en el como y el sobre todo en el por qué y en el cuando.

¿Que es la programación multihilo?

En estos tiempos todos los sistemas operativos (excepto quizá los educacionales) son sistemas operativos multitarea, esto quiere decir que pueden ejecutar varias tareas o procesos simulataneamente. Esto no siempre fue así, el ms-dos era un sistema monotarea lo que quiere decir que tan solo una tarea podía ejecutarse en el sistema simultaneamente.

Antes de lanzarnos a explicar la programación multihilo es conveniente hacer un repaso a ciertas caraterísticas de los sitemas operativos.

Delegados en Delphi. Pasando metodos y funciones como parametros.

Que es un delegado

Un delegado (de la palabra inglesa delegate) es un prototipo de función es decir, un esquema que debemos seguir al declarar una función. La palabra delegado proviene (o mejor dicho yo la escuche por primera vez) de C# y probablemente en delphi sería más conveniente referirse a ellas como tipos de funciones.

Los delegados se utilizan fundamentalmente para proporcionar tipado al paso de funciones como parametros a otras funciones o metodos.

Para que sirve un delegado

Si alguien ha programado alguna vez en C sabrá que pasar funciones como parametros esta a la orden del día, estas funciones suelen conocerse con el nombre de funciones de CallBack (algo así como "devuelveme la llamada") e implican que tu estás pasando una función como parametro que quieres que sea invocada cuando dicha función tenga unos ciertos datos preparados.

Una buena parte de las funciones de la API de windows funcionan de esta forma, por ejemplo si observamos la ayuda de la función EnumWindows de la API de windows (kernel32.dll):

La funcion EnumWindows enumera todas las ventans de alto nivel de la pantalla pasando el manejador de cada ventana a una funcion de callback definida por la aplicación. EnumWindows ejecuta hasta que la última ventana sea enumerada o hasta que la función de callback devuelva falso.

    BOOL EnumWindows(

    WNDENUMPROC lpEnumFunc,     // pointer to callback function
    LPARAM lParam       // application-defined value
   );

Uso de memoria en Delphi

Introducción

Hace poco me he encontrado en el trabajo con un programa que estaba haciendo estaba teniendo pérdidas de memoria, no demasiada cada vez pero si lo suficiente como para convertirse en un problema a medio plazo.

Cuando te encuentras un problema de consumo de memoria lo más habitual es mirar el código de la zona en la que piensas que puede estar el problema intentando encontrar el lugar donde consumes memoria que luego no vas a liberar, o bien recurrir a algún programa de monitorización de memoria que te ayude a encontrar dichos problemas (yo no he tenido suerte con ellos).

Puesto que el programa tiene demasiadas lineas de código para hacer una revisión al azar sin saber concretamente donde se producían las perdidas de memoria se me ocurrió que la forma más sencilla de acotar el problema sería ir monitorizando el uso de memoria del programa (esto así dicho suena muy facil pero en realidad no lo es tanto).

Un vistazo al .dpr

Cuando creamos un projecto nuevo en Delphi el IDE automáticamente crea un archivo con extensión dpr (delphi project) y, si el proyecto contiene forms, un archivo dfm (delphi form) por cada form del proyecto (y también una unidad .pas por cada uno).

El archivo con extensión dpr constituye un archivo de proyecto de Delphi. En el se encuentra recogido el código de inicialización de la aplicación así como todas las unidades y formularios del proyecto.

Delphi esta construido sobre el lenguaje de programación pascal, o más concretamente sobre Object Pascal que incluye el paradigma de objetos al lenguaje Pascal. Por ello conserva la organización inicial de pascal en casi su totalidad.

Por más que el IDE de desarrollo nos facilite las cosas y parezca que pasan 'mágicamente', lo cierto es que todo, absolutamente todo, lo que se programa desde delphi acaba siendo un programa de Object Pascal. Por ello lo primero que encontramos en el dpr es la sentencia program NombreDePrograma; seguida de las declaraciónes uses (las unidades y formularios que aparecen en el project viewer (del menu view, project viewer) se leen de aqui) seguido de la declaración de variables, declaración de funciones (normalmente ninguna puesto que el IDE nunca mete funciones aqui) y por último un begin y un end dentro de los cuales se crean los formularios de la aplicación.

Patrones de diseño. Memento Pattern.

Introducción

En muchas ocasiones deseamos guardar el estado de un objeto de forma que podamos recuperar dicho estado en cualquier momento. Un ejemplo muy simple es que vayamos a modificar una serie de parametros del objeto y hacer alguna operación pero deseemos almacenar en que estado estaba ese objeto para poder volver a él en caso de que se produzca una excepción.

En la mayoría de los objetos existe una parte de su estado que queda recogida en variables privadas. Al contrario de lo que se suela pensar una campo es privado no para evitar que alguien pueda modificarlo (que tangencialmente también) sino para indicar al programador que usa la clase que dicho campo no le interesa y no debe tenerlo en cuenta, utilizarlo ni depender en ningún sentido. Si cambiamos dichas variables de privadas a publicas, conseguimos que quien quiere guardar el estado pueda hacerlo leyendo y almacenando los campos pero violamos el concepto anterior.

El patrón memento enfrenta este problema encapsulando la información interna del objeto en una objeto, preferiblemente opaco al exterior.

Patrones de diseño. Facade Pattern

Introducción

El patrón Façade es un patrón de software cuyo objetivo se basa en simplificar o hacer más amigable la complejidad asociada a una librería software.

En ocasiones una librería o serie de librerias contienen una serie de funcionalidades para realizar diversas acciones. Si se analiza, en la gran mayoría de los proyectos de software, se observará que la mayor parte de las llamadas que recibe la librería es a las mismas funciones o a una combinación de ellas. Es decir, existe una gran cantidad de peticiones comunes que suelen ocurrir en el 90% de los casos y que satisfacen las necesidades del cliente de la librería. En estos casos, es convieniente crear un objeto que simplifica el API de la librería, unificando y simplicando ciertos procesos del API. Por supuesto algunos programas todavía querran (y podrán) acceder al viejo API de la librería para utilizar algunas funciones especializadas pero se habrá conseguido simplificar la funcionalidad más comunmente usada de la librería.

Patrones de diseño. Command Pattern

Introducción

El patrón Command (command pattern) es un patrón de diseño en el que los objetos representan acciones que serán consumidas por algún consumidor.

Problema

El patrón Command se utiliza para resolver diversos tipos de problemas en desarrollo de software:

  • Usado como simplificación de llamadas. En ocasiones el número de parámetros de una función crece hasta hacerse inmanejable. El uso del patrón command permite agrupar los parámetros en un solo objeto que se pasará a la función.
  • Usado como cola de comandos. Encapsular cada comando en un objeto permite su procesamiento de forma secuencial en forma de cola, de forma que un proceso trabajador pueda ir sacando los trabajos de dicha cola.
  • Operaciones con histórico. Usando objetos como comando y manteniendo esos comandos podemos mantener un histórico de los comandos utilizados y, en caso necesario, revertirlos.
  • Generalización de comandos. En ocasiones el uso de comandos permite la abstracción de dicho comando de forma que el comando constituye una clase abstracta de la que heredan los comandos específicos y que permite que un determinado objeto procese comandos ajustados a un determinado esquema independientemente de lo que haga dicho parámetro.