Está en la página 1de 10

MEMORIA COMPARTIDA. 1.Conceptos generales de memoria compartida.

La forma ms eficaz que tienen los procesos para comunicarse consiste en compartir una zona de memoria, tal que para enviar datos de un proceso a otro, slo se ha de escribir en dicha memoria y automticamente estos datos estarn disponibles para cualquier otro proceso. La utilizacin de este espacio de memoria comn evita la duplicacin de datos y el lento trasvase de informacin entre los procesos. La memoria convencional que puede direccionar un proceso a travs 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 violacin de segmento. Es decir, cuando se crea uno o ms procesos mediante la llamada fork(), se realiza una duplicacin de todas las variables usadas, de forma que cualquier modificacin de sus valores pasa inadvertida a los dems procesos, puesto que aunque el nombre es el mismo, su ubicacin en memoria no lo es. Esto es debido a que con cada nuevo proceso se reserva una zona de memoria inaccesible a los dems. Las direcciones de las variables de esta zona son virtuales, y es el mdulo de gestin de la memoria el que se encarga de traducirlas a direcciones fsicas. Para solucionar este problema, UNIX ofrece la posibilidad de crear zonas de memoria con la caracterstica de poder ser direccionadas por varios procesos simultneamente. A estas zonas de memoria se les denominada segmentos de memoria compartida, y corresponden a memoria virtual, es decir; sus direcciones fsicas asociadas pueden verse modificadas a lo largo de la ejecucin, pero esto es transparente al programa puesto que es el mdulo de gestin de la memoria el que se encarga de traducir las direcciones fsicas a las direcciones virtuales generadas por los procesos. El kernel no gestiona de forma automtica los segmentos de memoria compartida, por lo tanto, es necesario asociar a cada segmento o grupo de segmentos un conjunto de mecanismos de sincronizacin, de forma que se evite los tpicos choques entre los procesos, es decir, que un proceso este modificando la informacin contenida en el segmento mientras que otro lee sin que se hayan actualizado todos los datos.

2.-

Peticin de un segmento de memoria compartida.

La funcin shmget permite crear una zona de memoria compartida o habilitar el acceso a una ya creada. Su declaracin es la siguiente: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget (clave, tamao, opcin); key_t clave; int tamao; int opcin; /* clave del segmento de memoria compartida */ /* tamao del segmento de memoria compartida */ /* opcin para la creacin */

E.G.R.

Si la llamada se ejecuta correctamente, la funcin devolver el identificador asociado a la zona de memoria con el fin de poder utilizarla posteriormente. Si por algn motivo falla, la funcin devolver el valor 1. El parmetro clave es la llave de acceso, y tiene el mismo significado que el parmetro clave en la funcin semget que permite crear o habilitar grupos de semforos. El segundo parmetro, tamao, indica el espacio en bytes de la zona de memoria compartida que se desea crear. Este espacio es fijo durante su utilizacin. El ltimo parmetro es una mscara 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 mscara opcin de la citada funcin semget. El identificador del segmento que devuelve esta funcin es heredado por todos los procesos descendientes del que llama a esta funcin. El siguiente trozo de cdigo muestra cmo se crea una zona de memoria de 4096 bytes, donde slo el propietario va a tener permiso de lectura y escritura: #define LLAVE (key_t)234 int shmid; /* clave de acceso */

/* 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 funcin shmctl proporciona informacin administrativa y de control sobre el segmento de memoria compartida que se especifique. Su declaracin es la sigueinte: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmctl (shmid, op, p_buf); int shmid; int op; struct shnud_ds *p_buf; /* identificador del segmento */ /* operacin a efectuar */ /* argumento de la operacin */

Esta funcin va a actuar sobre el segmento de memoria compartida que responde al identificador shmid (devuelto por una llamada previa a shmget). El parmetro op indica el tipo de operacin de control que se desea realizar, y sus posibles valores vlidos son los que se especifican a continuacin:

E.G.R.

Operacin IPC_STAT

Efecto y valor devuelto Lee la informacin administrativa y la almacena en la zona de memoria apuntada por p_buf. IPC_SET Modifica la informacin administrativa, para lo cual dicha informacin debe estar en p_buf. IPC_RMID Indica al kernel que borre el segmento. Esto no se llevar a cabo mientras que exista algn 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 operacin slo 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 operacin slo la puede llevar a cabo el superusuario. La llamada a esta funcin devuelve el valor 0 si se ejecuta satisfactoriamente, y 1 si se ha producido algn fallo. El siguiente trozo de cdigo 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 direccin virtual en su espacio de direcciones (mapearlo), con el fin de que dicho proceso pueda acceder a l por medio de esta direccin. Esta operacin se conoce como conexin, unin o enganche de un segmento con el proceso. Una vez que el proceso deja de usar el segmento, debe de realizar la operacin inversa ( desconexin, desunin o desenganche), dejando de estar accesible el segmento para el proceso. Las llamadas al sistema para realizar estas operaciones son las siguientes: shmat Esta funcin realiza la conexin del segmento al espacio de direccionamiento del proceso. Su declaracin es: char *shmat (shmid, adr, opcion); int shmid; char *adr; int opcion;
E.G.R.

/* identificador del segmento */ /* direccin de enlace */ /* opcin de conexin */


3

Shmid es el identificador del segmento, adr es la direccin virtual donde se desea que empiece el segmento (esta direccin puede ser suministrada por el programador o bien elegida por el kernel) y opcion es una mscara 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 funcin funciona correctamente, devolver un puntero a la direccin virtual a la que est conectado el segmento. Esta direccin puede coincidir o no con adr, dependiendo de la decisin que tome el kernel. El problema principal que se plantea es el de la eleccin de la direccin, puesto que, no puede entrar en conflicto con direcciones ya utilizadas, o que impida el aumento del tamao de la zona de datos y el de la pila. Por ello, si se desea asegurar la portabilidad de la aplicacin es recomendable dejar al kernel la eleccin de comienzo del segmento, para ello basta con pasarle un puntero NULL como segundo parmetro (valor entero 0). Si por algn motivo falla la llamada a esta funcin, devolver 1. Una vez que el segmento esta nido al espacio de direcciones virtuales del proceso, el acceso a l se realiza a travs de punteros, como con cualquier otra memoria dinmica de datos asignada al programa. shmdt Efecta el desenlace del segmento previamente conectado. Su declaracin es: int shmdt (adr); char *adr; /* direccin de conexin del segmento a desenlazar */

Su nico parmetro adr, es la direccin virtual del segmento que se desea desconectar (devuelta por la llamada a la funcin shmat). Es lgico que despus de ejecutarse esta funcin, dicha direccin se convierta en una direccin 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 funcin devolver el valor 0, y en caso de que se produzca algn fallo devolver 1. El siguiente trozo de cdigo 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; .... /* Creacin de un segmento de memoria compartida */ if((shmid=shmget(LLAVE, MAX*sizeof(char), IPC_CREAT | 0600)) == -1) {

E.G.R.

printf(No se ha podido crear el segmento.); exit (-1); } else { /* Conexin del segmento al espacio de direcciones virtuales */ if(((int)vector=shmat(shmid, 0, 0)) == -1) { printf( Error en la conexin.); exit(-1); } /* Manipulacin 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]); /* Desconexin del segmento al espacio de direcciones virtuales */ if(shmdt(vector) == -1) { printf( Error en la desconexin.); exit(-1); } /* Borrado del segmento de memoria compartida */ if(shmctl(shmid, IPC_RMID, 0) == -1) { printf( Error en el borrado del segmento.); exit(-1); } } ...

Obtener un sgmento de memoria


shmget

- obtiene un segmento de memoria compartida.

Sintaxis
#include <sys/shm.h> int shmget( key_t

key,

size_t

size,

int

shmflg);

Descripcin La funcin shmget retorna el identificador de memoria compartida asociada a key. Un identificador de memoria compartida y la estructura de datos asociada se crearn para key si una de las siguientes condiciones se cumple:
E.G.R. 5

- Si key es igual a IPC_PRIVATE. Cuando esto ocurre se crear un nuevo identificador, si existen disponibilidades, este identificador no ser devuelto por posteriores invocaciones a shmget mientras no se libere mediante la funcin shmctl. El identificador creado podr ser utilizado por el proceso invocador y sus descendientes; sin embargo esto no es un requerimiento. El segmento podr ser accedido por cualquier proceso que posea los permisos adecuados. - Si key an no tiene asociado un identificador de memoria compartida y adems shmflg & IPC_CREAT es verdadero. Como consecuencia de la creacin, la estructura de datos asociada al nuevo identificador se inicializa de la siguientes manera: shm_perm.cuid y shm_perm.uid al identificador de usuario efectivo del proceso invocador,shm_perm.gcuid y shm_perm.guid al identificador de grupo efectivo del proceso invocador, los 9 bits menos significativos de shm_perm.mode se inicializan a los 9 bits menos significativos del parmetro shmflg,shm_segsz al valor especificado por size, shm_ctime a la fecha y hora que el sistema posea en el momento de la invocacin y por ltimo se ponen a cero shm_lpid, shm_nattach, shm_atime y shm_dtime. Si la ejecucin se realiza con xito, entonces retornar un valor no negativo denominado identificador de segmento compartido. En caso contrario, retornar -1 y la variable global errno tomar en cdigo del error producido.

Vincular un rea de memoria compartida


shmat, shmdt

- funciones de operacin sobre memoria compartida.

Sintaxis
#include <sys/shm.h> char *shmat( int

shmid,

void *shmaddr, int

shmflg

);

int shmdt( void *shmaddr )

Descripcin asocia el segmento de memoria compartida especificado por shmid al segmento de datos del proceso invocador. Si el segmento de memoria compartida an no haba sido asociado al proceso invocador, entoncesshmaddr debe tener el valor de cero y el segmento se asocia a una posicin en memoria seleccionado por el sistema operativo. Dicha localizacin ser la misma en todos los procesos que acceden al objeto de memoria compartida. Si el segmento de memoria compartida ya haba sido asociado por el proceso invocador, shmaddr podr tener un valor distinto de cero, en ese caso deber tomar la direccin asociada actual del segmento
shmat

E.G.R.

referenciado por shmid. Un segmento se asocia en modo slo lectura si shmflg & SHM_RDONLY es verdadero; si no entonces se podr acceder en modo lectura y escritura.. No es posible la asociacin en modo slo escritura. Si la funcin se ejecuta con xito, entonces retornar la direccin de comienzo del segmento compartido, si ocurre un error devolver -1 y la variable global errno tomar el cdigo del error producido. desasocia del segmento de datos del proceso invocador el segmento de memoria compartida ubicado en la localizacin de memoria especificada por shmaddr. Si la funcin se ejecuta sin error, entonces devolver 0, en caso contrario retornar -1 y errno tomar el cdigo del error producido.
shmdt

Operaciones de control
- Realiza operaciones de control en una regin de memoria compartida.
shmctl

Sintaxis
#include <sys/shm.h> int smctl(int

shmid,

int

cmd,

struct shmid_ds *buff);

Descripcin La funcin shmctl permite realizar un conjunto de operaciones de control sobre una zona de memoria compartida identificada por shmid. El argumento cmd se usa para codificar la operacin solicitada. Los valores admisibles para este parmetro son:
IPC_STAT:

lee la estructura de control asociada a shmid y la deposita en la estructura apuntada por buff.
IPC_SET:

actualiza los campos shm_perm.uid, shm_perm.gid y shm_perm.mode de la estructura de control asociada a shmid tomando los valores de la estructura apuntada por buff.
IPC_RMID:

elimina el identificador de memoria compartida especificado por shmid del sistema, destruyendo el segmento de memoria compartida y las estructuras de control asociadas. Si el segmento est siendo utilizado por ms de un proceso, entonces la clave asociada toma el valor IPC_PRIVATE y el segmento de memoria es eliminado, el segmento desaparecer cuando el ltimo proceso que lo utiliza notifique su desconexin del segmento. Esta operacin slo la podrn utilizar aquellos procesos que posean privilegios de acceso a recurso apropiados, para llevar a cabo esta comprobacin el sistema considerar el identificador de usuario efectivo del proceso y lo comparar con los campos shm_perm_id y shm_perm_cuid de la estructura de control asociada a la regin de memoria compartida.

E.G.R.

SHM_LOCK:

bloquea la zona de memoria compartida especificada por shmid. Este comando slo puede ejecutado por procesos con privilegios de acceso apropiados.
SHM_UNLOCK:

desbloquea la regin de memoria compartida especificada por shmid. Esta operacin, al igual que la anterior, slo la podrn ejecutar aquellos procesos con privilegios de acceso apropiados. La funcin shmctl retornar el valor 0 si se ejecuta con xito, o -1 si se produce un error, tomando adems la variable global errno el valor del cdigo del error producido.

Creacin de zonas de memoria compartida


Para crear zonas de memoria compartida utilizaremos la funcin shmget de una manera similar a los semforos y colas de mensajes. #include <sys/ipc.h> #include <sys/shm.h> int shmget (key_t clave, int tam, int flag); Devuelve -1 en caso de error y un identificador de la zona de memoria compartida en caso de xito. Ese identificador lo utilizaremos para trabajar con la zona de memoria compartida. key_t clave clave de la zona de memoria compartida. int tam tamao en bytes de la zona de memoria compartida si queremos crearla. Si queremos acceder a un rea ya creada, el tamao ser 0. int flag permisos. Se indican de la misma manera que los semforos y colas de mensajes. Ejemplo El siguiente fragmento de cdigo crea una zona de memoria compartida del tamao de una variable entera. La zona de memoria tendr permisos de escritura y lectura slo para el propietario.

Vinculacin de memoria compartida


Ya hemos creado la memoria compartida, pero para utilizarla necesitamos saber su direccin (observe que shmget no nos la indica). Para utilizar la memoria compartida debemos antes vincularla con alguna variable de nuestro cdigo. De esta manera, siempre que usemos la variable vinculada estaremos utilizando la variable compartida. Para establecer un vnculo utilizamos la funcin shmat. void *shmat(int shmid, const void *shmaddr, int shmflag) Devuelve la direccin de memoria de comienzo de la memoria compartida o -1 si hubo algn error. int shmid identificador de la memoria compartida obtenido con shmget. const void *shmaddr Direccin concreta donde reside la memoria compartida. No lo vamos a utilizar por lo que su valor siempre ser NULL. int shmflag permisos. Por ejemplo. Aunque hayamos obtenido una zona de memoria con permiso para escritura o lectura, podemos vincularla a una variable para solo lectura. Si no queremos cambiar los permisos usamos 0. SHM_RND: Indica que la direccin de la memoria debe redondearse a la direccin de la pgina de memoria ms cercana. No la utilizaremos. SHM_RDONLY: Indica que la memoria compartida ser de solo lectura. Ejemplo El siguiente fragmento de cdigo recupera la direccin de la zona de memoria compartida obtenida en el ejemplo anterior y coloca en ella el valor 10. Observe que, como la direccin de memora corresponde con un valor entero, la almacenamos en un puntero a entero. Observe tambin como se realiza adecuadamente la comprobacin de errores. int *entero; entero = (int *)shmat(shmid, NULL, 0); if (entero == (int *)-1) { perror(Obteniendo direccin de memoria compartida);

E.G.R.

return -1; } (*entero)=10; Cuando ya no vamos a utilizar ms la variable vinculada, hemos de desvincularla antes de poder eliminar la memoria compartida. Para ello utilizamos la funcin shdmt. int shmdt(const void *shmaddr) Devuelve -1 si hubo algn error, otro valor en caso contrario. Observe que el -1 devuelto no es de tipo entero sino de tipo puntero a entero, es decir, el puntero apunta a la posicin de memoria -1. const void *shmaddr Variable vinculada a la memoria compartida. Ejemplo El siguiente fragmento desvincula la memoria compartida vinculada en el ejemplo anterior. r = shmdt(entero); if (r == -1) perror(Error desvinculando memoria compartida); Ojo, esta funcin slo libera el vnculo, pero no elimina la zona de memoria compartida. Adems los vnculos se pierden al llamar a las funciones exit o exec.

Borrado de memoria compartida


Como los dems recursos IPC, la memoria compartida reservada seguir estando presente en el sistema hasta que no la borremos explcitamente. Para ello utilizamos la funcin memctl de una forma muy similar a como borramos grupos de semforos o colas de procesos. int shmctl(int shmid,int cmd, struct shmid_ds *buf) Devuelve -1 si error, u otro valor en caso contrario. int shmid identificador de la memoria compartida obtenido con shmget. int cmd - alguna de las siguientes constantes: IPC_STAT: Nos rellena la estructura shmid_ds() con los datos que maneja el ncleo en lo referente a la zona de memoria compartida. IPC_SET: Lo contrario de lo anterior establece la estructura que le pasamos como parmetro en el kernel. IPC_RMID: Borra el recurso. Algunos sistemas, como Linux o SunOS, soportan tambin las constantes SHM_LOCK y SHM_UNLOCK para bloquear o desbloquear el acceso a memoria compartida. struct sumid_ds *buf - para el comando de borrado no es necesario el tercer argumento, por lo que utilizaremos NULL. Ejemplo La siguiente lnea borra la zona de memoria compartida que hemos utilizado en los ejemplos anteriores. r = shmctl(shmid, IPC_RMID, NULL); if (r == -1) perror(Error desvinculando memoria compartida); Ojo, la operacin de borrado slo es efectiva si ningn proceso tiene vinculada la memoria compartida. Si an existen vnculos a la memoria compartida, la operacin de borrado se pospone hasta que desaparezca el ltimo vnculo. La estructura shmid se muestra a continuacin struct shmid_ds{ struct ipc_perm shm_perm; //Permisos int shm_segsz; //Tamao del rea time_t shm_atime; //Hora del ltimo smhmat time_t shm_dtime; //Hora del ltimo shmdt() time_t shm_ctime; //Hora del ltimo shmctl() unsigned short shm_cpid; //Pid del creador unsigned short shm_lpid; //Pid del ultimo que hizo shmctl() short shm_nattach; //Num. de procesos conectados } La estructura ipc_perm se muestra a continuacin: struct ipc_perm { ushort cuid; ushort cgid; ushort uid; ushort gid; E.G.R. 9

ushort mode; ushort seq; key_t key; };

E.G.R.

10