Obstack

20 04 2008 Programación
Obstack es otros de los medios que emplea la librería C de GNU para la asignación dinámica de memoria. Obstack es una pila de objetos (datos) que puede crecer dinámicamente. Es posible crear cualquier número de obstacks para, en cada uno, ir almacenando diferentes conjuntos de datos. En cada obstack el último objeto en entrar es el primero en salir.

    Obstack es pues otro de los métodos de la librería glibc para la reserva dinámica de memoria.

    A parte de esta limitación en el orden de almacenaje obstack es capaz de contener cualquier número de objetos de cualquier tamaño. Obstack está implementado con macros, de manera que la asignación de espacio es muy rápida si los objetos son pequeños. La única sobrecarga por objeto es el relleno necesario para colocar un objeto en unos límites adecuados.

    Para la creación de un obstack debes primero incluir el archivo de cabecera obstack.h. En este archivo se declara la estructura obstack de tamaño fijo y que registra el estado del obstack y como encontrar el espacio donde los objetos están localizados. No se debe intentar acceder al contenido de esta estructura directamente sino que se debe utilizar las funciones diseñadas especificamente para obstack.

    Obstack puede ser tratado como cualquier otro tipo de objetos, puedes crear obstack dinamicamente o crear obstacks que contengan a su vez otros obstacks.

    Todas las funciones que trabajan con obstacks necesitan que se les especifique el obstack a usar. Se hace esto a través de un puntero a la estructura de tipo struct obstack* .

    Los objetos dentro del obstack son empaquetados en bloques llamados chunks. La estructura obstack apunta a una cadena de chunks actualmente en uso.

    La librería obstack obtiene un nuevo chunk cada vez que debe insertar un nuevo objeto que no cabe en un chunk anterior. La librería administra automáticamente estos chunks de manera que no hay que prestarles demasiada atención, pero hay que propocionar una función a la librería obstack para que esta se haga con un nuevo chunk. Generalmente se debe proporcionar un a función que emplea malloc directa o indirectamente. También se debe proporcionar una función que libere el chunk (free).

Ejemplo:

#include //declara todas las variables, funciones y macros necesarios para obstack

//Estas dos macros definen los métodos para la generación de memoria dinámica y su liberación
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free

...

//función que se llamara en el caso de error en la reserva dinámica de memoria
void my_obstack_alloc_failed(void)
{
...
}

...

//Declaramos nuestra estructura obstack
static struct obstack myobstack;

...

//La inicializamos
obstack_init(&myobstack);

...

//Declaramos que función será llamada en caso de error al reservar memoria dinámica
obstack_alloc_failed_handler = &my_obstack_alloc_failed;

//Grabamos en nuestro obstack la cadena "hola mundo"
obstack_alloc("hola mundo",11);

Para almacenar un bloque con un contendio específico utilizamos la función obstack_copy

void* obstack_copy (struct obstack* obstack-ptr, void* address, int size)

La función obstrack_copy0 además agrega un caracter nulo (ascii 0) al final.

void* obstack_copy0 (struct obstack* obstack-ptr, void* address, int size)

En el último argumento size no debemos tener en cuenta este carácter nulo extra. Ejemplo:

char*
obstack_savestring (char* addr, int size)
{
return obstack_copy0 (&myobstack, addr, size);
}

    Para liberar objetos en el obstack se emplea obstack_free

void obstack_free (struct obstack* obstack-ptr, void* object)

    Si objeto es un puntero nulo, todo lo almacenado en obstack será liberado. Cualquier otro valor debe ser un puntero a un objeto del obstack. Ese objeto será liberado y todos los que se encuentran a continuación de él.

    Observa que si object es un puntero nulo, el resultado será un obstack no inicializado. Para liberar todos los objetos del obstack pero dejando el obstack válido para agregar nuevos objetos tenemos que pasarle como object el primer objeto almacenado.

    Recuerda que obstack está agrupado en chunks. Si se liberan todos los objetos de un chunk, obstack automaticamente liberará este chunk para que pueda ser utilizado como recurso para otros elementos del programa.

    Recordemos que los interfaces definidos en obstack pueden estar definidos como funciones o como macros. Ejemplo:

char* x;
void* (* funcp) ();
/* Use the macro. */
x = (char* ) obstack_alloc (obptr, size);
/* Call the function. */
x = (char* ) (obstack_alloc) (obptr, size);
/* Take the address of the function. */
funcp = obstack_alloc;

    Si empleas otro compilador que no sea el de GNU debes tener esto en cuenta.

Para saber más:


GNU C Library Obstacks



Bookmark Obstack  at del.icio.us Digg Obstack Mixx Obstack Bloglines Obstack Technorati Obstack Fark this: Obstack Bookmark Obstack  at YahooMyWeb Bookmark Obstack  at Furl.net Bookmark Obstack  at reddit.com Bookmark Obstack  at blinklist.com Bookmark Obstack  at Spurl.net Bookmark Obstack  at NewsVine Bookmark Obstack  at Simpy.com Bookmark Obstack  at blogmarks Bookmark Obstack  with wists Bookmark Obstack  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Realloc y calloc

14 04 2008 Programación
Como ya habiamos comentado en un anterior post sobre la asignación de memoria dinámica además de malloc que asigna un zona de memoria para nuestra programa tanto realloc como calloc hacen exactamente lo mismo pero además tienen capacidades adicionales (que las hacen maś caras computacionalmente hablando, así que si no necesitas ninguna de estas características utliliza directamente malloc. Sino estarás malgastando recursos).

La función calloc cuya firma o prototipo es la siguiente:

void* calloc(size_t nmemb, size_t size);

Inicializa la zona de memoria reservada. Como se puede observar sus argumentos son diferentes de las de la función malloc que sólo recibía el número de bytes a reservar. Para calloc es necesario dar el número de elementos a reservar y el tamaño de cada uno de esos elementos. Así tenemos que por ejemplo:

int* pi;
pi = calloc(50,sizeof(int));

Reservará espacio para 50 enteros asignando al puntero pi la dirección en memoria del primero.

La función realloc por otra parte intenta cambiar el tamaño de una zona de memoria previamente asignada dinamicamente copiando, si es posible, su contenido anterior.

Esta es su firma:

void* realloc(void* ptr, size_t size);

Si el cambio de tamaño no se puede llevar a cabo entonces la función devolverá un puntero a null

ip = (int* ) realloc ( ip, 25*sizeof(int) );

Siguiendo el primer ejemplo este redimensionará la zona de memoria asignada por la función calloc. Debemos tener en cuenta que esta función puede modificar además el valor del puntero. Recolocando la zona de memoria reservada en otra zona de la memoria de la máquina dependiendo de la situación. Incluso una disminución en el tamaño de la memoria puede dar lugar a una recolocación del segmento de memoria.

Como con malloc y calloc toda memoria reservada dinámicamente debe ser liberada con free.

void free(void* ptr);




Bookmark Realloc y calloc  at del.icio.us Digg Realloc y calloc Mixx Realloc y calloc Bloglines Realloc y calloc Technorati Realloc y calloc Fark this: Realloc y calloc Bookmark Realloc y calloc  at YahooMyWeb Bookmark Realloc y calloc  at Furl.net Bookmark Realloc y calloc  at reddit.com Bookmark Realloc y calloc  at blinklist.com Bookmark Realloc y calloc  at Spurl.net Bookmark Realloc y calloc  at NewsVine Bookmark Realloc y calloc  at Simpy.com Bookmark Realloc y calloc  at blogmarks Bookmark Realloc y calloc  with wists Bookmark Realloc y calloc  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Reserva de memoria en glibc

09 04 2008 Programación
Glibc proporciona varias funciones para reservar memoria bajo el control explícito del programa. Cada una de estas funciones varían en cuanto a eficiencia:

  • La familia de funciones malloc permite una reserva de memoria completamente genérica.
  • Obstack es otra familia de funciones menos genérica pero más eficiente para reservar memoria tipo pila.
  • Y la función alloca te permite reservar espacio de almacenamiento dinámicamente que será liberada automáticamente.


  • Las funciones tipo malloc son las más empleadas debido a su versatilidad (aunque haya que pagar un coste en eficiencia). Está es la firma de la función malloc

    void *malloc(size_t number_of_bytes);

    Su empleo es muy sencillo, si quieres reservar digamos 300 bytes debes pasarle ese número como parámetro y la función, en caso de éxito, te devolverá un puntero al comienzo de esa zona de 300 bytes reservada para ti. En caso de error devuelve un puntero a NULL (generalmente debido a una falta de memoria). El puntero a void, el tipo del valor de retorno, simplemente nos permite, mediante un cast (implicito), emplear cualquier tipo de datos para su almacenamiento. El tipo size_t es simplemente un unsigned int definido en varios archivos de cabecera stdio.h, stddef.h, stdlib.h, and string.h:

    typedef unsigned int size_t;


    por ejemplo

    char *micadena;
    micadena = malloc(200);

    Intentará hacer que el puntero micadena apunte al comienzo de una zona reservada para ti de 200 bytes o retornando un puntero a null en caso de fallo.

    El operador sizeof (atención no es una función aunque lo parezca) se utiliza muy a menudo en conjunción con malloc ya que este nos devuelve el número de bytes que ocupa un determinado tipo de datos que se le pasa como argumento, así:

    sizeof(int);
    sizeof(char);
    sizeof(miEstructura);

    Nos devolverá el tamaño que ocupa en bytes un entero un caracter o una estructura definida por nosotros respectivamente. Siguiendo nuestro ejemplo para reservar espacio para una cadena de 200 caracteres la forma más correcta tras todo esto sería:

    char *micadena;
    micadena = malloc(sizeof(char)*200);
    if(!micadena)
    {
    printf("Error fatal. No hay suficiente memoria\n);
    }

    sizeof puede ser usado para encontrar el tamaño de cualquier tipo de datos, variables o estructuras. Simplemente debes proporcionale uno de estos como argumento. Pongo otro ejemplo de esto:

    int i;
    struct COORD {float x,y,z};
    typedef struct COORD PT;

    i = sizeof(int);
    i = sizeof(i);
    i = sizeof(struct COORD);
    i = sizeof(PT);

    Todas las lineas anteriores son válidas.

    Una función que si debería estar siempre acompañando a malloc es la función free. Se encarga de liberar la memoria que previamente hemos reservado, su firma es la siguiente:

    void free(void *ptr);

    y el puntero que le debemos pasar como argumento es obviamente el que nos devolvió la función malloc. Un error relativamente común cuando empleamos malloc es no utilizar free para liberar la memoria cuando ya no la necesitamos. Esta es la causa principal de los llamados "memory leaks" o "porque mi programa consume desenfrenadamente más y más memoria".

    Una nota sobre malloc: malloc NUNCA inicializa el bloque de memoria que acaba de reservar. Si crees por ejemplo que ese bloque debe contener byes a cero estas equivocado, puede contener cualquiera valores (basura).

    Para no hacer este post más extenso comentaré en otro proximamente las funciones realloc y calloc cuyo propósito es idéntico aunque tienen nuevas características (que también los hacen más caros computancionalmente hablando)

    Para saber más:
    Librería C de GNU

Bookmark Reserva de memoria en glibc  at del.icio.us Digg Reserva de memoria en glibc Mixx Reserva de memoria en glibc Bloglines Reserva de memoria en glibc Technorati Reserva de memoria en glibc Fark this: Reserva de memoria en glibc Bookmark Reserva de memoria en glibc  at YahooMyWeb Bookmark Reserva de memoria en glibc  at Furl.net Bookmark Reserva de memoria en glibc  at reddit.com Bookmark Reserva de memoria en glibc  at blinklist.com Bookmark Reserva de memoria en glibc  at Spurl.net Bookmark Reserva de memoria en glibc  at NewsVine Bookmark Reserva de memoria en glibc  at Simpy.com Bookmark Reserva de memoria en glibc  at blogmarks Bookmark Reserva de memoria en glibc  with wists Bookmark Reserva de memoria en glibc  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Glibc

09 04 2008 Programación
En este pequeño post haré una pequeña introducción sobre la librería Glibc. Aunque sobradamente conocida su estudio en la mayoría de los casos es muy superficial. Tener al menos una visión global de las rutinas que implementa esta librería desarrollada por GNU es básica en muchos entornos de programación.

Empecemos por el principio y por lo más obvio (es decir, las perogrulladas). Glibc es una librería C que proporciona al lenguaje rutinas básicas de la que este carece. Rutinas para, por ejemplo, la manipulación de cadenas, operaciones de entrada y salida, administración de memoria, búsqueda en directorios y un largo etcétera. Glibc es quizá la librería más importantes en sistemas GNU/Linux - GNU/Hurd y una de las de mayor tamaño. De hecho el compilador gcc agrega por defecto está librería a la hora de iniciar la compilación y enlace de código. glibc significa GNU C Library y contiene todas las librerías especificadas por el estándar ANSI C además de características adicionales especificas de POSIX y otras derivadas de sistemas UNIX y también algunas específicas de sistemas GNU, claro.

Glibc como cualquier otra librería empleada en programas C realmente consiste en 2 partes: ficheros de cabeceras que definen tipos, macros y declaran variables y funciones; y la librería real o archivo que contiene las definiciones de las variables y funciones.

En sistemas GNU/Linux los ficheros de cabecera con todas estas declaraciones se encuentran en /usr/include mientras que la librería en sí está en /lib bajo el nombre libc-{numero-version}.so (libc-2.3.6.so en mi máquina).

Recuerda que en C, una declaración solamente proporciona información de que una función o variable existe y le asigna un tipo. Para una declaración de una función, nos puede dar además información sobre los tipos de sus argumentos. El propósito de las declaraciones es permitir que el compilador procese correctamente referencias a funciones o variables declaradas. Una definición, sin embargo, asigna espacio de almacenamiento para una variable o dice que hace una función.

Para usar las facilidades que nos proporciona librería GNU C, debes asegurarte que las fuentes de tu programa incluyen los archivos de cabecera correctos. De esta manera el compilador tendrá las declaraciones adecuadas y podrá procesar correctamente las referencias a ellas. Una vez que el programa haya sido compilado, el enlazador resolverá estas referencias proporcionadas por el archivo que contiene la librería.

Los archivos de cabecera son incluidos en las fuentes del programa mediante la directiva de preprocesador #include. El lenguaje C soporta dos tipos de directiva, la primera,

#include "header"

típicamente usada para incluir ficheros de cabecera escritos por ti mismo; esto contendrá definiciones y declaraciones describiendo interfaces entre las diferentes partes de una aplicación. Por el contrario,

#include <file.h>

Se emplea para incluir archivos de cabecera que contienen definiciones y declaraciones de una librería estándar. Esta librería normalmente ha sido instalada por el administrador del sistema. Deberías emplear esta segunda forma para añadir los archivos de cabecera de la librería C.

La primera forma buscará la librería en el directorio local, si no se especifica una ruta; y la segunda buscará el fichero de cabecera en el directorio marcado para tal fin dentro del sistema (/lib).

Bookmark Glibc  at del.icio.us Digg Glibc Mixx Glibc Bloglines Glibc Technorati Glibc Fark this: Glibc Bookmark Glibc  at YahooMyWeb Bookmark Glibc  at Furl.net Bookmark Glibc  at reddit.com Bookmark Glibc  at blinklist.com Bookmark Glibc  at Spurl.net Bookmark Glibc  at NewsVine Bookmark Glibc  at Simpy.com Bookmark Glibc  at blogmarks Bookmark Glibc  with wists Bookmark Glibc  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Firefox 3 beta 5

04 04 2008 Programación
Mozilla acaba de hacer disponible la beta 5 de su navegador. La aplicación viene con muchas mejoras: mejor rendimiento con javascript, eliminación de los memory leaks, mayor compatibilidad con los estándares web (obtiene un 71 sobre 100 en la prueba acid3), widgets nativos y ha solucionado una gran cantidad de bugs respecto a la beta anterior.

    El cambio más controvertido ha sido el del número de conexiones abiertas simultaneas con los servidores webs. En versiones anteriores de firefox el máximo de conexiones abiertas era de 2 (que es lo considerado correcto según los estandares). Subiendo este máximo se obtiene una mejora muy importante en la velocidad a la que se cargan las páginas a costa de generar una carga superior en los servidores. Este aumento en el número de conexiones ya lo han realizado otros navegadores como Internet Explorer u Opera a riesgo de aumentar las posibilidades de congestión de los sitios web.

    Puedes mirar estos cambios en la página about:config del firefox en los valores:

network.http.max-connections 30
network.http.max-connections-per-server 15
network.http.max-persistent-connections-per-proxy 8
network.http.max-persistent-connections-per-server 6
network.http.pipelining.maxrequests 4

    El valor al que hacemos referencia es el de max-persistent-connections-per-server que pasa de 2 a 6 respecto a versiones anteriores. Los otros valores también han sido aumentados para subir la velocidad al descargar las páginas.

    Estas son algunas gráficas de zdnet.com sobre el rendimiento comparativo de esta beta:

Comparativa rendimiento javascript entre diferentes navegadores

Resultado de las pruebas de ACID3 de diferentes navegadores

Este es el historial de lanzamientos de la versión Gran Paradiso de firefox (aka firefox 3.0)

Fx 3.0a1/Gecko 1.9a1 - LANZADO: 8 de Diciembre del 2006
Fx 3.0a2/Gecko 1.9a2 - LANZADO: 7 de Febrero del 2007
Fx 3.0a3/Gecko 1.9a3 - LANZADO: 23 de Marzo
Fx 3.0a4/Gecko 1.9a4 - LANZADO: 28 de Abril
Fx 3.0a5/Gecko 1.9a5 - LANZADO: 6 de Junio
Fx 3.0a6/Gecko 1.9a6 - LANZADO: 2 de Julio
Fx 3.0a7/Gecko 1.9a7 - LANZADO: 3 de Agosto
Fx 3.0a8/Gecko 1.9a8 - LANZADO: 20 de Septiembre
Fx 3.0b1/Gecko 1.9b1 - LANZADO: 20 de Noviembre
Fx 3.0b2/Gecko 1.9b2 - LANZADO: 18 de Diciembre
Fx 3.0b3/Gecko 1.9b3 - LANZADO: 12 de Febrero del 2008
Fx 3.0b4/Gecko 1.9b4 - LANZADO: 10 de Marzo del 2008
Fx 3.0b5/Gecko 1.9b5 - LANZADO: 2 de Abril del 2008
Firefox 3 Final - ESTIMADO: Junio

    Me da la espina que puede que saquen otra beta (o varias 'releases for comments') antes de la primera versión final

Bookmark Firefox 3 beta 5  at del.icio.us Digg Firefox 3 beta 5 Mixx Firefox 3 beta 5 Bloglines Firefox 3 beta 5 Technorati Firefox 3 beta 5 Fark this: Firefox 3 beta 5 Bookmark Firefox 3 beta 5  at YahooMyWeb Bookmark Firefox 3 beta 5  at Furl.net Bookmark Firefox 3 beta 5  at reddit.com Bookmark Firefox 3 beta 5  at blinklist.com Bookmark Firefox 3 beta 5  at Spurl.net Bookmark Firefox 3 beta 5  at NewsVine Bookmark Firefox 3 beta 5  at Simpy.com Bookmark Firefox 3 beta 5  at blogmarks Bookmark Firefox 3 beta 5  with wists Bookmark Firefox 3 beta 5  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Complejidad algorítmica

22 03 2008 Programación
    Como ya habíamos afirmado en el artículo sobre la medición de la complejidad, un algoritmo se puede clasificar en cuando a su eficiencia o coste en una de la siguientes categorías. De mayor eficiencia a menor, siendo n el tamaño del problema a tratar:

* Complejidad constante (la mejor y objetivo a buscar) O(1)
* Complejidad logarítmica (muy buena) O(log n)
* Complejidad lineal O(n)
* Complejidad lineal*logarítmica O(n log n)
* Complejidad cuadrática O(n2)
* Complejidad polinomial (mala) O(na) con a>2
* Complejidad exponencial (muy mala) O(an) con a>2
* Complejidad factorial (la peor, problemas generalmente intratables) O(n!)

    Tenemos pues que en cuanto a complejidad algorítmica:

1 << log n << n << nlog n << n2 << n3 << ... << 2n << n!

    A menor orden menos recursos se necesitarán para llevar a cabo la resolución del problema, menor coste.

    Lo que nos puede interesar a continuación es obtener un conjunto de reglas prácticas que no sirvan para determinar la complejidad de un algoritmo y así por ejemplo poder comparar varios algoritmos y determinar cual es el mejor. Estas reglas no pueden por desgracia, tras seguirlas detenidamente, llevarnos a determinar con exactitud el coste de un algoritmo pero son útiles para ayudarnos en este empeño.

    Estas reglas deben tener en consideración los costes de:

*Instrucciones simples
*Composición de instrucciones
*Instrucciones de selección
*Bucles
*Subprogramas

    Los 3 elementos a continuación tienen una ejecución en tiempo (coste) constante, O(1)

* Instrucciones simples: la evaluación de expresiones aritméticas siempre que estas sean de tamaño constante así como la comparación de datos simples.
*Las operaciones de asignación, lectura y escritura de datos simples
*Accesos a elementos de un array, a un campo de un registro y a la siguiente posición de un registro de un archivo

    La composición de instrucciones que dependan del tamaño n del problema el coste será igual a la suma de los costes.

    Para las instrucciones de selección en que varios partes del código pueden ser o no ejecutadas según la condición que defina la selección se toma como coste el coste de la peor rama.

    Para los bucles si estos dependen del tamaño del problema se considera orden lineal, pero si están anidados por cada anidación que dependa del tamaño del problema multiplicaremos por n el coste dando lugar a coste cuadráticos, polinómicos o incluso exponenciales

    Para subprogramas resulta de aplicar las anteriores reglas al subprograma, si el número de llamadas al subprograma depende del tamaño del programa (tener en cuenta posibles recursividades) el orden sera mayor dependiendo de como crezca el número de llamadas con el tamaño.

    Si se descompone el coste en partes tenemos que el coste de la unión de cada parte es igual a la que tiene un costo mayor. Es decir si tenemos una parte con un coste lineal y a continuación otra parte con coste cuadrático la unión de las dos nos dará un coste cuadrático (regla de la suma)

    Vamos a continuación a poner dos implementaciones en C de dos algoritmos diferentes para llevar a cabo el mismo problema. Se trata de, a partir de dos números enteros distintos, obtener la suma de todos los números que hay entre ellos incluidos ellos mismos. Por ejemplo si tenemos el 5 y el 10 el algoritmo debe ser capaz de calcular la suma:

5+6+7+8+9+10



Continua leyendo "Complejidad algorítmica"


Bookmark Complejidad algorítmica  at del.icio.us Digg Complejidad algorítmica Mixx Complejidad algorítmica Bloglines Complejidad algorítmica Technorati Complejidad algorítmica Fark this: Complejidad algorítmica Bookmark Complejidad algorítmica  at YahooMyWeb Bookmark Complejidad algorítmica  at Furl.net Bookmark Complejidad algorítmica  at reddit.com Bookmark Complejidad algorítmica  at blinklist.com Bookmark Complejidad algorítmica  at Spurl.net Bookmark Complejidad algorítmica  at NewsVine Bookmark Complejidad algorítmica  at Simpy.com Bookmark Complejidad algorítmica  at blogmarks Bookmark Complejidad algorítmica  with wists Bookmark Complejidad algorítmica  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

Clone en Linux

19 03 2008 Programación
    La función clone realiza una tarea similar a fork, crear procesos hijos al proceso que lo ejecuta. A diferencia del fork, clone permite que el proceso hijo comparta partes de su contexto de ejecución con el proceso padre, como el espacio de memoria, la tabla de descriptores de fichero y la tabla de manejadores de señales (signal handler). El uso que habitualmente se le da a clone es para implementar hilos de ejecución (threads): múltiples hilos de ejecución de control en un programa que corre en un espacio de memoria compartido.

 La función clone está definida en el archivo de cabecera sched.h y esta es su firma:

int clone (int (*fn) (void *), void *child_stack, int flags, void *arg);

    Cuando se crea un proceso hijo con clone se ejecuta la función fn(arg). El argumento fn es un puntero a una función. El entero que debe retornar esa función será el código de salida del proceso hijo. El proceso hijo podría también finalizar explicitamente mediante una llamada a exit o después de recibir una señal fatal.

    El argumento child_stack especifica la posición de la pila usada por el proceso hijo. Ya que el proceso hijo y el padre pueden compartir la misma memoria, no es posible que el proceso hijo ejecute la misma pila que el proceso padre. El proceso padre (el que invoca la función clone) prepara un espacio de memoria para la pila del hijo y le pasa un puntero a este espacio mediante este argumento.

    El argumento entero flag es un OR de varias constantes que especifican que es compartido entre padre e hijo:

CLONE_PARENT, CLONE_FS, CLONE_FILES, CLONE_NEWSNS, CLONE_SIGHAND, CLONE_PTRACE, CLONE_UNTRACED, CLONE_STOPPED, CLONE_VFORK, CLONE_VM, CLONE_PID, CLONE_THREAD, CLONE_SYSVEM, CLONE_SETTLS, CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARID

    clone es una función que realiza un llamada de sistema (system call) a sys_clone que sólo precisa los argumentos flags y child_stack que tienen el mismo significado que para el caso de la función.

    La función clone retorna el TID (Thread ID, identificador del hilo) o -1 en caso de fallo y errno será asignado apropiadamente describiendo el error.

    A continuación vemos un ejemplo sencillo de la utilización de esta función:


#include <sched.h>
#include <stdio.h>
#include <time.h>
#include <malloc.h>

int cloneando()
{
printf("Hola mundo clonado\n");
}
int main(int argc,char** argv)
{
void **pila_hijo;
pila_hijo = malloc(1000);
clone(cloneando,pila_hijo, CLONE_VM|CLONE_FILES, NULL);
sleep(1);
printf("Hola mundo real\n");

return 0;
}


    Espero que el articulo os sirva de ayuda, pero si necesitáis alguna aclaración escribid un comentario a este artículo

Bookmark Clone en Linux  at del.icio.us Digg Clone en Linux Mixx Clone en Linux Bloglines Clone en Linux Technorati Clone en Linux Fark this: Clone en Linux Bookmark Clone en Linux  at YahooMyWeb Bookmark Clone en Linux  at Furl.net Bookmark Clone en Linux  at reddit.com Bookmark Clone en Linux  at blinklist.com Bookmark Clone en Linux  at Spurl.net Bookmark Clone en Linux  at NewsVine Bookmark Clone en Linux  at Simpy.com Bookmark Clone en Linux  at blogmarks Bookmark Clone en Linux  with wists Bookmark Clone en Linux  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!

wait, waitpid y waitid, gestión de múltiples procesos

18 03 2008 Programación
    Tras ver como se pueden generar varios procesos empleando fork ahora veremos como podemos controlar sus tiempos de ejecución con wait, waitpid y waitid.

    Esta es la firma de las dos primeras funciones:

pid_t wait(int *status)
pid_t waitpid(pid_t pid, int *status, int options)

    Estas funciones se utilizan para esperar hasta que un proceso cambie de estado. Se emplean como ya hemos comentado para esperar por un cambio de estado en un proceso hijo del proceso que realiza la llamada ha estas funciones. Un cambio de estado para el proceso hijo puede ser uno de estos 3: el hijo ha muerto, el hijo ha sido detenido por una señal o el hijo continua su ejecución tras recibir una señal apropiada (resume).

    Si el hijo ha cambiado de estado antes de la ejecución del wait entonces la llamada a esta función retornará inmediatamente. En caso contrario la llamada bloqueará el proceso hasta que se produzca este cambio de estado.

    wait() espera hasta que uno cualquiera de los hijos del proceso que realiza la llamada a wait cambie de estado. waitpid en su lugar suspende la ejecución del proceso actual hasta que el hijo, especificado por el argumento pid cambie su estado. Por defecto, waitpid espera sólo por la muerte de los hijos, pero este comportamiento es modificable mediante el parámetro options.

    El valor de pid puede tomar estos valores

    Más pequeño que -1 hace que se espere por cualquier hijo cuyo id de proceso de grupo sea igual al valor absoluto de este argumento. Igual a -1 esperará por cualquier hijo, el primero en cambiar de estado (igual comportamiento que wait), cero indica que se esperará por cualquier proceso hijo que tenga el mismo id de grupo de procesos y mayor que cero hará que se espere por el hijo cuyo pid coincida con este valor.

    El parámetro optiones es una máscara OR de diversos constantes, sólo las enumeraré pero es sencillo encontrar información sobre ellas utilizando el comando man: WHOHANG, WUNTRACED, WCONTINUED, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG y WIFCONFIRMED

    Existe además otra función llamada waitid que realiza una función análoga a las anteriores pero proporciona un mayor control sobre que cambios de estado en el hijo deben ser esperados. La firma de la función es la siguiente

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)

    Los archivos de cabecera donde se definen estas 3 funciones y las constantes y tipos necesarios para su utilización están en los archivos de cabecera sys/types.h y sys/wait.h

    Los parámetros id e idtype seleccionan a que hijo(s) se debe esperar, options tiene el mismo significado que en el caso de waitpid().

    En cuanto a los los parámetros que retornas estas tres funciones wait() en caso de éxito devuelve el pid del proceso hijo que ha cambiado de estado. En caso de error devuelve -1. waitpid() en caso de éxito devuelve lo mismo que wait() y en caso de error -1 pero si se ha especificado la constante WHOHANG la función no bloquea y devuelve cero si no hay ningún hijo que haya cambiado de estado. Por último waitid() devuelve cero en caso de éxito o si WHOHANG ha sido activado y no hay hijo que haya cambiado de estado y -1 en caso de error.

    Volviendo a nuestro programa fork vamos ha hacerle unas modificaciones para que el padre espere a la muerte de sus 2 hijos:


#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
pid_t pid1, pid2;
int status1, status2;

if ( (pid1=fork()) == 0 )
{ /* hijo */
printf("Hijo 1 (%d, hijo de %d)\n", getpid(), getppid());
}
else
{ /* padre */
if ( (pid2=fork()) == 0 )
{ /* segundo hijo */
printf("Hijo 2 (%d, hijo de %d)\n", getpid(), getppid());
}
else
{ /* padre */
/* Esperamos al primer hijo */
waitpid(pid1, &status1, 0);
/* Esperamos al segundo hijo */
waitpid(pid2, &status2, 0);
printf("Padre (%d, hijo de %d)\n", getpid(), getppid());
}
}

return 0;
}



    waitpid hace que se espere hasta que terminen los dos hijos identificados en el programa por pid1 y pid2

    Para compilar y ejecutar este programa copia el fragmento de código en un fichero llamado forks.c y después en el mismo directorio donde lo has grabado ejecuta las siguientes líneas

$ gcc forks.c
$ ./a.out

Recuerda que para ver la pid de la shell donde ejecutas el programa debes ejecutar:

$ echo $$





Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at del.icio.us Digg wait, waitpid y waitid, gestión de múltiples procesos Mixx wait, waitpid y waitid, gestión de múltiples procesos Bloglines wait, waitpid y waitid, gestión de múltiples procesos Technorati wait, waitpid y waitid, gestión de múltiples procesos Fark this: wait, waitpid y waitid, gestión de múltiples procesos Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at YahooMyWeb Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at Furl.net Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at reddit.com Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at blinklist.com Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at Spurl.net Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at NewsVine Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at Simpy.com Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at blogmarks Bookmark wait, waitpid y waitid, gestión de múltiples procesos  with wists Bookmark wait, waitpid y waitid, gestión de múltiples procesos  at Ma.gnolia.com wong it! Bookmark using any bookmark manager! Stumble It!