memoria

7
MÓDULO II: PROGRAMACIÓN CONCURRENTE MEMORIA COMPARTIDA. 1.- Conceptos generales de memoria compartida. La forma más eficaz que tienen los procesos para comunicarse consiste en compartir una zona de memoria, tal que para enviar datos de un proceso a otro, sólo se ha de escribir en dicha memoria y automáticamente estos datos estarán disponibles para cualquier otro proceso. La utilización de este espacio de memoria común evita la duplicación de datos y el lento trasvase de información entre los procesos. La memoria convencional que puede direccionar un proceso a través de su espacio de direcciones virtuales es local a ese proceso y cualquier intento de direccionar esa memoria desde otro proceso va a provocar una violación de segmento. Es decir, cuando se crea uno o más procesos mediante la llamada fork(), se realiza una duplicación de todas las variables usadas, de forma que cualquier modificación de sus valores pasa inadvertida a los demás procesos, puesto que aunque el nombre es el mismo, su ubicación en memoria no lo es. Esto es debido a que con cada nuevo proceso se reserva una zona de memoria inaccesible a los demás. Las direcciones de las variables de esta zona son virtuales, y es el módulo de gestión de la memoria el que se encarga de traducirlas a direcciones físicas. Para solucionar este problema, UNIX ofrece la posibilidad de crear zonas de memoria con la característica de poder ser direccionadas por varios procesos simultáneamente. A estas zonas de memoria se les denominada segmentos de memoria compartida, y corresponden a memoria virtual, es decir; sus direcciones físicas asociadas pueden verse modificadas a lo largo de la ejecución, pero esto es transparente al programa puesto que es el módulo de gestión de la memoria el que se encarga de traducir las direcciones © E.G.R. 1

Upload: adilene-santiago

Post on 02-Aug-2015

25 views

Category:

Business


0 download

TRANSCRIPT

Page 1: Memoria

MÓDULO II: PROGRAMACIÓN CONCURRENTE

MEMORIA COMPARTIDA.

1.- Conceptos generales de memoria compartida.

La forma más eficaz que tienen los procesos para comunicarse consiste en compartir una zona de memoria, tal que para enviar datos de un proceso a otro, sólo se ha de escribir en dicha memoria y automáticamente estos datos estarán disponibles para cualquier otro proceso. La utilización de este espacio de memoria común evita la duplicación de datos y el lento trasvase de información entre los procesos.

La memoria convencional que puede direccionar un proceso a través de su espacio de direcciones virtuales es local a ese proceso y cualquier intento de direccionar esa memoria desde otro proceso va a provocar una violación de segmento. Es decir, cuando se crea uno o más procesos mediante la llamada fork(), se realiza una duplicación de todas las variables usadas, de forma que cualquier modificación de sus valores pasa inadvertida a los demás procesos, puesto que aunque el nombre es el mismo, su ubicación en memoria no lo es. Esto es debido a que con cada nuevo proceso se reserva una zona de memoria inaccesible a los demás. Las direcciones de las variables de esta zona son virtuales, y es el módulo de gestión de la memoria el que se encarga de traducirlas a direcciones físicas.

Para solucionar este problema, UNIX ofrece la posibilidad de crear zonas de memoria con la característica de poder ser direccionadas por varios procesos simultáneamente. A estas zonas de memoria se les denominada segmentos de memoria compartida, y corresponden a memoria virtual, es decir; sus direcciones físicas asociadas pueden verse modificadas a lo largo de la ejecución, pero esto es transparente al programa puesto que es el módulo de gestión de la memoria el que se encarga de traducir las direcciones físicas a las direcciones virtuales generadas por los procesos.

El kernel no gestiona de forma automática los segmentos de memoria compartida, por lo tanto, es necesario asociar a cada segmento o grupo de segmentos un conjunto de mecanismos de sincronización, de forma que se evite los típicos choques entre los procesos, es decir, que un proceso este modificando la información contenida en el segmento mientras que otro lee sin que se hayan actualizado todos los datos.

2.- Petición de un segmento de memoria compartida.

La función shmget permite crear una zona de memoria compartida o habilitar el acceso a una ya creada. Su declaración es la siguiente:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

int shmget (clave, tamaño, opción);

key_t clave; /* clave del segmento de memoria compartida */

© E.G.R. 1

Page 2: Memoria

int tamaño; /* tamaño del segmento de memoria compartida */int opción; /* opción para la creación */Si la llamada se ejecuta correctamente, la función devolverá el identificador

asociado a la zona de memoria con el fin de poder utilizarla posteriormente. Si por algún motivo falla, la función devolverá el valor –1.

El parámetro clave es la llave de acceso, y tiene el mismo significado que el parámetro clave en la función semget que permite crear o habilitar grupos de semáforos.

El segundo parámetro, tamaño, indica el espacio en bytes de la zona de memoria compartida que se desea crear. Este espacio es fijo durante su utilización.

El último parámetro es una máscara de bits que definirá los permisos de acceso a la zona de memoria y el modo de adquirir el identificador de la misma. En definitiva, su significado es similar al que se vio para la máscara opción de la citada función semget.

El identificador del segmento que devuelve esta función es heredado por todos los procesos descendientes del que llama a esta función.

El siguiente trozo de código muestra cómo se crea una zona de memoria de 4096 bytes, donde sólo el propietario va a tener permiso de lectura y escritura:

#define LLAVE (key_t)234 /* clave de acceso */

int shmid; /* identificador del nuevo segmento de memoria compartida */

if((shmid=shmget(LLAVE, 4096, IPC_CREAT | 0600)) == -1) {

/* Error al crear o habilitar el segmento de memoria compartida. Tratamiento del error. */

}

3.- Control de un segmento de memoria compartida.

La función shmctl proporciona información administrativa y de control sobre el segmento de memoria compartida que se especifique. Su declaración es la sigueinte:

#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>

int shmctl (shmid, op, p_buf);

int shmid; /* identificador del segmento */int op; /* operación a efectuar */struct shnud_ds *p_buf; /* argumento de la operación */

Esta función va a actuar sobre el segmento de memoria compartida que responde al identificador shmid (devuelto por una llamada previa a shmget). El parámetro op

© E.G.R. 2

Page 3: Memoria

indica el tipo de operación de control que se desea realizar, y sus posibles valores válidos son los que se especifican a continuación:

Operación Efecto y valor devueltoIPC_STAT Lee la información administrativa y la almacena en la zona de

memoria apuntada por p_buf.IPC_SET Modifica la información administrativa, para lo cual dicha

información debe estar en p_buf.IPC_RMID Indica al kernel que borre el segmento. Esto no se llevará a cabo

mientras que exista algún proceso conectado al mismo. Sin embargo, su efecto inmediato es evitar que cualquier proceso se enganche a partir de ahora al segmento.

SHM_LOCK Bloquea en memoria el segmento, es decir; permanece fijo en memoria y no se va a realizar sobre él swapping. Esta operación sólo la puede efectuar el superusuario.

SHM_UNLOCK Desbloquea el segmento, pudiendo los mecanismos de swapping trasladarlo de la memoria principal a la secundaria, y viceversa. Esta operación sólo la puede llevar a cabo el superusuario.

La llamada a esta función devuelve el valor 0 si se ejecuta satisfactoriamente, y –1 si se ha producido algún fallo.

El siguiente trozo de código muestra como se borra un segmento de memoria compartida previamente creado:

int shmid; /* identificador del segmento de memoria compartida */....

if(shmctl (shmid, IPC_RMID,0) == -1) {

/* Error al eliminar el segmento de memoria compartida. Tratamiento del error. */

}

4.- Operaciones con segmentos de memoria compartida.

Un proceso, antes de usar un segmento de memoria compartida, tiene que atribuirle una dirección virtual en su espacio de direcciones (mapearlo), con el fin de que dicho proceso pueda acceder a él por medio de esta dirección. Esta operación se conoce como conexión, unión o enganche de un segmento con el proceso. Una vez que el proceso deja de usar el segmento, debe de realizar la operación inversa (desconexión, desunión o desenganche), dejando de estar accesible el segmento para el proceso.

Las llamadas al sistema para realizar estas operaciones son las siguientes:

shmat Esta función realiza la conexión del segmento al espacio de direccionamiento del proceso. Su declaración es:

char *shmat (shmid, adr, opcion);

© E.G.R. 3

Page 4: Memoria

int shmid; /* identificador del segmento */char *adr; /* dirección de enlace */int opcion; /* opción de conexión */

Shmid es el identificador del segmento, adr es la dirección virtual donde se desea que empiece el segmento (esta dirección puede ser suministrada por el programador o bien elegida por el kernel) y opcion es una máscara de bits que indica la forma de acceso al segmento de memoria. Si el bit SHM_RDONLY está activo, el segmento será accesisble para leer, pero no para escribir.

Si la llamada a esta función funciona correctamente, devolverá un puntero a la dirección virtual a la que está conectado el segmento. Esta dirección puede coincidir o no con adr, dependiendo de la decisión que tome el kernel. El problema principal que se plantea es el de la elección de la dirección, puesto que, no puede entrar en conflicto con direcciones ya utilizadas, o que impida el aumento del tamaño de la zona de datos y el de la pila. Por ello, si se desea asegurar la portabilidad de la aplicación es recomendable dejar al kernel la elección de comienzo del segmento, para ello basta con pasarle un puntero NULL como segundo parámetro (valor entero 0). Si por algún motivo falla la llamada a esta función, devolverá –1.

Una vez que el segmento esta únido al espacio de direcciones virtuales del proceso, el acceso a él se realiza a través de punteros, como con cualquier otra memoria dinámica de datos asignada al programa.

shmdt Efectúa el desenlace del segmento previamente conectado. Su declaración es:

int shmdt (adr);

char *adr; /* dirección de conexión del segmento a desenlazar */

Su único parámetro adr, es la dirección virtual del segmento que se desea desconectar (devuelta por la llamada a la función shmat). Es lógico que después de ejecutarse esta función, dicha dirección se convierta en una dirección ilegal del proceso. Esto no quiere decir que su contenido se borre, simplemente que se deja de tener acceso a la memoria reservada.

Si la llamada se efectua satisfactoriamente, la función devolverá el valor 0, y en caso de que se produzca algún fallo devolverá –1.

El siguiente trozo de código muestra como se puede crear un segmento de memoria compartida y almacenar en él un vector de caracteres:

#define LLAVE (key_t)234#define MAX 10

int shmid, i;char *vector;

....

© E.G.R. 4

Page 5: Memoria

/* Creación de un segmento de memoria compartida */if((shmid=shmget(LLAVE, MAX*sizeof(char), IPC_CREAT | 0600)) == -1) {

printf(“No se ha podido crear el segmento.”);exit (-1);

} else {

/* Conexión del segmento al espacio de direcciones virtuales */if(((int)vector=shmat(shmid, 0, 0)) == -1) {

printf(“ Error en la conexión.“);exit(-1);

}

/* Manipulación del segmento de memoria compartida */for (i=0; i<MAX; i++)

vector[i]=’a’;for (i=0; i<MAX; i++)

printf(“Valor almacenado %c”, vector[i]);

/* Desconexión del segmento al espacio de direcciones virtuales */if(shmdt(vector) == -1) {

printf(“ Error en la desconexión.“);exit(-1);

}

/* Borrado del segmento de memoria compartida */if(shmctl(shmid, IPC_RMID, 0) == -1) {

printf(“ Error en el borrado del segmento.“);exit(-1);

}}...

© E.G.R. 5