jueves, 18 de diciembre de 2014

Ejemplo de manejo de MEMORIA COMPARTIDA en Linux

Para manejar memoria compartida basta con realizar estos tres pasos:


Lo primero es crear la clave para la memoria compartida. Para ello se usa la función ftok que recibe dos parámetros: La ruta de un fichero existente y un número para generar la clave:

// Se crea la clave para la memoria compartida
clave = ftok ("/bin/ls", 34);

Luego creamos la memoria con la clave conseguida. Para ello usamos shmget
El primer parámetro es la clave
El segundo es la cantidad de bytes que se va a ocupar la memoria. En este caso queremos reservar espacio para un solo entero.
El tercero son los flags (permisos y modos). IPC_CREAT indica que debe crear la zona de memoria si esta no existe. En caso de que exista la usa de igual forma. Si se le agrega IPC_EXCL falla si el id ya existe. Esto para evitar usar una zona que ya este en uso o creada.

// Se crea la memoria compartida
id_Memoria = shmget (clave,  sizeof(int)*1,  0777 | IPC_CREAT);

Por último obtenemos la dirección de la memoria compartida y la guardamos en un puntero. para ello usamos shmat. El primer parametro es el id que obtuvimos con shmget. El resto de parámetros basta con colocarlos en cero :) 
// Se apunta a la dirección de memoria compartida 
memoriaCompartida = (int *)shmat (id_Memoria, (char *)0, 0);
Con estos tres pasos ya podemos usar la memoria compartida.
En este ejemplo vemos a dos procesos:

* Restador: Decrementa el valor de la memoria compartida.
* Sumador:  Incrementa el valor de la memoria compartida.
En la memoria compartida estará alojado un entero


Este es el código del sumador. El del restador es casi igual, solo que en vez de incrementar decrementa.
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <stdlib.h>

using namespace std;

int main()
{
    key_t clave=0;
    int id_Memoria=0;    
    
    int *memoriaCompartida = NULL;

    // Se crea la clave para la memoria compartida
    clave = ftok ("/bin/ls", 34);   
    if (clave == -1){
        cout << "No consigo clave para memoria compartida" << endl;
        exit(0);
    }

    // Creamos la memoria con la clave recién conseguida. Para ello llamamos
    // a la función shmget pasándole la clave, el tamaño de memoria que
    // queremos reservar (100 enteros en nuestro caso) y unos flags.
    // Los flags son  los permisos de lectura/escritura/ejecucion
    // para propietario, grupo y otros (es el 777 en octal) y el
    // flag IPC_CREAT para indicar que cree la memoria.
    // La función nos devuelve un identificador para la memoria recién
    // creada.
    //
    id_Memoria = shmget (clave, sizeof(int)*1, 0777 | IPC_CREAT);
    if (id_Memoria == -1)    {
        cout << "No consigo Id para memoria compartida" << endl;
        exit (0);
    }

    //
    // Una vez creada la memoria, hacemos que uno de nuestros punteros
    // apunte a la zona de memoria recién creada. Para ello llamamos a
    // shmat, pasándole el identificador obtenido anteriormente y un
    // par de parámetros extraños, que con ceros vale.
    //
    memoriaCompartida = (int *)shmat (id_Memoria, (char *)0, 0);
    if (memoriaCompartida == NULL)
    {
        cout << "No consigo memoria compartida" << endl;
        exit (0);
    }

    // Ya podemos utilizar la memoria.
    // Escribimos cosas en la memoria. Los números de 1 a 10 esperando
    // un segundo entre ellos. Estos datos serán los que lea el otro
    // proceso.
    //
    while (true)
    {
        // Incrementa el valor en memoria compartida
        memoriaCompartida[0]++;
        cout<<"Valor del entero en Memoria compartida = "<<memoriaCompartida[0]<<endl;
        fflush(stdout);
        sleep(1);
    }

    // shmdt desasocia una region de memoria compartida del espacio
    //  de direcciones virtuales del proceso
    //
    shmdt ((char *)memoriaCompartida);

    // Marca el ID de la memoria para ser destruido:
    // NO DESTRUYE la memoria, solo la marca.
    // Cuando se muere el ultimo proceso asociado a esa
    // memoria entonces el sistema se encarga de borrar la
    // memoria
    shmctl (id_Memoria, IPC_RMID, (struct shmid_ds *)NULL);
}
Puedes descargar el ejemplo DESDE AQUI.




1 comentario: