15
JOSÉ ANTONIO MÉNDEZ BARRIOS OTOÑO 2015 – PRÁCTICA 9 1.INTRODUCCION 1. ¿Qué es la memoria compartida? La memoria compartida es uno de los mecanismos agrupados bajo el nombre de Inter Process Comunication (IPC), junto con semáforos y colas de mensajes (FIFO)que tienen disponibles los sistemas Unix basados en System V, entre ellos los S.O-Linux. Como se verá, el mecanismo es muy similar al funcionamiento de los semáforos y de las colas de mensajes. Mediante memoria compartida, como su nombre indica, podemos crear zonas de memoria compartidas por varios procesos. De este modo los cambios que un proceso realice a los valores almacenados en memoria compartida son visibles para los demás procesos que utilicen esa misma memoria compartida. Por este motivo, en algunos casos será necesario garantizar el acceso en exclusiva para evitar inconsistencias en los datos mediante mecanismos ya vistos como señales o semáforos. Por ejemplo, si dos procesos acceden a la vez a esta área y intentan modificarla seguramente la modificación no será correcta. Este recurso IPC es el más rápido de los tres, ya que una vez conectados no necesitamos hacer más llamadas al sistema, ni interactuar con el núcleo; directamente escribimos o leemos gracias un puntero que referencia a la memoria compartida. A continuación se muestra una tabla comparativa de los tres mecanismos. Semáforos Colas mensajes Memoria compartida Archivo de cabecera sys/sem.h sys/msg.h sys/shm.h Creación / Obtención semget(…) msgget(…) shmget(…) Control semctl(…) msgctl(…) shmctl(…) Operaciones Subir / bajar p/v Poner / quitar mensaje Vincular / desvincular 2. Creación de zonas de memoria compartida Para crear zonas de memoria compartida utilizaremos la función shmget de una manera similar a los semáforos y colas de mensajes. #include <sys/ipc.h> #include <sys/shm.h> int shmget (key_t clave, int tam, int flag);

Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

JOSÉ ANTONIO MÉNDEZ BARRIOS OTOÑO 2015 – PRÁCTICA 9

1.INTRODUCCION

1. ¿Qué es la memoria compartida?

La memoria compartida es uno de los mecanismos agrupados bajo el nombre de Inter Process Comunication (IPC), junto con semáforos y colas de mensajes (FIFO)que tienen disponibles los sistemas Unix basados en System V, entre ellos los S.O-Linux.

Como se verá, el mecanismo es muy similar al funcionamiento de los semáforos y de las colas de mensajes.

Mediante memoria compartida, como su nombre indica, podemos crear zonas de memoria compartidas por varios procesos. De este modo los cambios que un proceso realice a los valores almacenados en memoria compartida son visibles para los demás procesos que utilicen esa misma memoria compartida. Por este motivo, en algunos casos será necesario garantizar el acceso en exclusiva para evitar inconsistencias en los datos mediante mecanismos ya vistos como señales o semáforos.

Por ejemplo, si dos procesos acceden a la vez a esta área y intentan modificarla seguramente la modificación no será correcta.

Este recurso IPC es el más rápido de los tres, ya que una vez conectados no necesitamos hacer más llamadas al sistema, ni interactuar con el núcleo; directamente escribimos o leemos gracias un puntero que referencia a la memoria compartida.

A continuación se muestra una tabla comparativa de los tres mecanismos.

Semáforos Colas mensajes Memoria compartida

Archivo de cabecera sys/sem.h sys/msg.h sys/shm.h Creación / Obtención semget(…) msgget(…) shmget(…) Control semctl(…) msgctl(…) shmctl(…) Operaciones Subir / bajar p/v Poner / quitar mensaje Vincular / desvincular

2. Creación de zonas de memoria compartida

Para crear zonas de memoria compartida utilizaremos la función shmget de una manera

similar a los semáforos y colas de mensajes.

#include <sys/ipc.h>

#include <sys/shm.h>

int shmget (key_t clave, int tam, int flag);

Page 2: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

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: tamaño en bytes de la zona de memoria compartida si queremos crearla. Si

queremos acceder a un área ya creada, el tamaño será 0.

int flag: permisos. Se indican de la misma manera que los semáforos y colas de

mensajes.

Ejemplo: El siguiente fragmento de código crea una zona de memoria compartida del tamaño

de una variable entera. La zona de memoria tendrá permisos de escritura y lectura sólo para

el propietario.

int shmid;

shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | IPC_EXCL

| S_IRUSR | S_IWUSR);

if (shmid == -1)

perror(“Error creando memoria compartida.”);

3. Vinculación de memoria compartida

Una vez ya creada la memoria compartida, pero para utilizarla necesitamos saber su

dirección (observe que shmget no nos la indica). Para utilizar la memoria compartida

debemos antes vincularla con alguna variable de nuestro código. De esta manera, siempre

que usemos la variable vinculada estaremos utilizando la variable compartida. Para

establecer un vínculo utilizamos la función shmat.

void *shmat(int shmid, const void *shmaddr, int shmflag)

Devuelve la dirección de memoria de comienzo de la memoria compartida o -1 si hubo

algún error.

int shmid : identificador de la memoria compartida obtenido con shmget.

const void *shmaddr:– Dirección 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 dirección de la memoria debe redondearse a la dirección

de la página de memoria más cercana. No la utilizaremos.

Page 3: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

SHM_RDONLY: Indica que la memoria compartida será de solo lectura.

Ejemplo 1:

El siguiente fragmento de código recupera la dirección de la zona de memoria compartida obtenida

en el ejemplo anterior y coloca en ella el valor 10. Observe que, como la dirección de memora

corresponde con un valor entero, la almacenamos en un puntero a entero.

Observe también como se realiza adecuadamente la comprobación de errores.

int *entero;

entero = (int *)shmat(shmid, NULL, 0);

if (entero == (int *)-1) {

perror(“Obteniendo dirección de memoria compartida”);

return -1;

}

(*entero)=10;

Cuando ya no vamos a utilizar más la variable vinculada, hemos de desvincularla antes de poder

eliminar la memoria compartida. Para ello utilizamos la función shdmt.

int shmdt(const void *shmaddr)

Devuelve -1 si hubo algún 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 posición de

memoria -1.

const void *shmaddr – Variable vinculada a la memoria compartida.

4. Borrado de memoria compartida

Como los demás recursos IPC, la memoria compartida reservada seguirá estando presente en el

sistema hasta que no la borremos explícitamente. Para ello utilizamos la función memctl de una

forma muy similar a como borramos grupos de semáforos 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 núcleo

en lo referente a la zona de memoria compartida.

• IPC_SET: Lo contrario de lo anterior establece la estructura que le pasamos como

parámetro en el kernel.

Page 4: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

• IPC_RMID: Borra el recurso.

Algunos sistemas, como Linux o SunOS, soportan también 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.

La siguiente línea 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”);

La estructura shmid se muestra a continuación

struct shmid_ds{

struct ipc_perm shm_perm; //Permisos

int shm_segsz; //Tamaño 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 continuación:

struct ipc_perm {

ushort cuid;

ushort cgid;

ushort uid;

ushort gid;

ushort mode;

ushort seq;

key_t key;

};

Page 5: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

PROGRAMA #1

PLANTEAMIENTO

Programa que se encarga de reservar memoria para una variable tipo entero

SOLUCION

ENTRADA: se creara una zona de memoria compartida la cual utilizaremos para la funcionalidad del

programa.

PROCESO: se hace la creación de 3 variables la primera de tipo entero que es la que utilizaremos para

identificar la zona de memoria que crearemos, la segunda de tipo entero pero declarada como un apuntador

que será la dirección de enlace a la memoria, la tercera será el numero que guardaremos en la memoria

compartida de tipo entero y declarado como apuntador, a continuación se procede a crear la zona de

memoria compartida mediante la función shmget junto con los parámetros requeridos como lo son la clave

de la zona de memoria el tamaño de la zona de memoria junto con los atributos que tendrá la zona de

memoria, se hace una sentencia para verificar que no exista en caso de que si lo único que se hace es

otorgarle el atributo que queremos en este caso el de escritura, a continuación se enlaza a un proceso

mediante la función shmat la cual tiene como parámetros el identificador de la zona el valor donde comienza

la misma y los permisos correspondientes después del enlace se libera la zona de memoria compartida en

caso de no realizarlo podría causar problemas como la perdida de información, la liberación de la zona de

memoria compartida se hace mediante la función shmctl(shm, IPC_RMID, 0).

SALIDA: se imprime el mensaje de creando zona de memoria, si no hubo algún problema se imprime el

letrero cree la zona de memoria y por último se imprime el valor de la variable.

Page 6: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

CODIGO EN C

#include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <errno.h> int main () { int shm ; /* identificador de la zona de memoriacompartida */ int * dir ; /* direccion de enlace de la memoria con los datos */ int * numero ; /* numero que guardamos en la memoria compartida */ printf(“Estoy creando la memoria compartida\n") ; /* creo la zona de memoria compartida */ shm = shmget(3000, sizeof(int), IPC_CREAT|IPC_EXCL|SHM_R|SHM_W) ; if ( shm == -1 && errno == EEXIST) shm = shmget(3000, sizeof(int), SHM_R|SHM_W) ; printf ( “Cree la zona de memoria %d\n", shm) ; /* lo enlazo a un proceso */ dir = (int *) shmat ( shm, NULL, 0) ; if ( dir == (int *)-1) { perror("error de enlace\n") ; exit(-1) ; } /* utilizo la informacion */ numero = (int *) dir ; *numero = 0 ; printf("%d", *numero) ; /* libero la memoria */

if ( shmdt(dir) == -1) {

("error de liberacion\n") ; exit(-1) ;

} else {

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

perror("error de borrado fisico\n") ; exit(-1) ;

} } exit(0) ; }

Page 7: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

CORRIDAS

Page 8: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM
Page 9: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

PROGRAMA #2

PLANTEAMIENTO

Programas en los cuales uno de ellos actúa como productor de números aleatorios y el segundo actuara como

un consumidor tomara los números generados y los imrpimira.

SOLUCION:

ENTRADA: se crean 2 programas un productor y un consumidor.

PROCESO: en el código del programa productor; se insertan las bibliotecas necesaria, se definen ya un

tamaño máximo para un ciclo for que se utilizara además de que se define ya la clave que se utilizara para la

creación de la zona de memoria, se crean las variables para el identificador de la zona y la variable para

enlazar además de la variable i la cual utilizaremos para un ciclo for que acontinuacion de utilizara, a

continuación se crea la zona de memoria compartida con shmget y el valor que esta devuelve se le asigna a

shmid a continuación se enlaza mediante shmat se hace una sentencia para verificar que no haya errores en

el enlace, después se utiliza srand que se encargara de crear los números aleatorios los cuales se iran

guardando en donde apunte nuestra variable srd que es la variable que utilizamos para enlazar.

El código del consumidor es similar al del productor esto viendo desde el punto de vista de que ambos

apuntan a la misma zona de memoria compartida en el caso del consumidor lo que hace es tomar los

números aleatorios que el productor ha creado y los imprime.

SALIDA: el programa del consumidor imprime los valores que el productor creo.

CODIGO EN C

//productor

#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/types.h> #include <sys/shm.h> #define TAMANIO 64 #define CLAVE (key_t) 1000 main(){ int shmid; int *adr; int i;

if((shmid=shmget(CLAVE,TAMANIO*sizeof(int), IPC_CREAT|0666))==-1){ perror("shmget"); exit(2); }

Page 10: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

if((adr=shmat(shmid,0,0)) == (int *) -1){ perror("shmat"); exit(2); }

srand(getpid()); for(i=0;i<TAMANIO;i++) printf("%d ",adr[i]=rand()%100); putchar('\n');

}

//consumidor

#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/shm.h> #define TAMANIO 64 #define CLAVE (key_t) 1000 main(){ int shmid;

int *adr; int i;

if((shmid=shmget(CLAVE,TAMANIO*sizeof(int), IPC_CREAT|0666))==-1){ perror("shmget"); exit(2);

} if((adr=shmat(shmid,0,0)) == (int *) -1){

perror("shmat"); exit(2); }

srand(getpid()); for(i=0;i<TAMANIO;i++) printf("%d ",adr[i]; putchar('\n'); }

Page 11: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

CORRIDAS

Page 12: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM
Page 13: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

PROGRAMA #3

PLANTEAMIENTO

Proceso padre e hijo que manejan una pila de enteros

SOLUCION

ENTRADA: se crean 3 programa uno para la inicialización del semáforo a ocupar, otro para las operaciones con

los semáforos, el siguiente el código del programa que se esta realizando además de un fichero sem.h donde

se incluyen varias librerías.

PROCESO: se crean 2 identificadores para la zona de memoria cada uno de ellos será utilizado por el padre e

hijo respectivamente

SALIDA: se muestran mensajes de tope del padre e hijo asi como el momento en el que el padre e hijo han

alcanzado su nivel máximo de capacidad.

CODIGO EN C

/* initsem.c – programa utilizado en ejemplo

anterior */

/* semopera.c -- operacion con semaforo */

#include "sem.h"

semopera(int semid, int numsem, int op){

struct sembuf buf;

buf.sem_num=numsem;

buf.sem_op=op;

buf.sem_flg=SEM_UNDO;

if (semop(semid, &buf, 1) == -1) {

perror("semop fallo");

exit(1);

}

else return 0;

}

/* Compila: cc memoria.c initsem.c semopera.c -o

memoria

Archivos necesarios: memoria.c initsem.c

semopera.c sem.h */

#include <sys/shm.h>

#include <sys/wait.h>

#include <signal.h>

#include "sem.h"

#define MAX 20

struct cc{

int pila[MAX];

};

main(){

int shm1, shm2, semid, i=0;

Page 14: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

int p;

key_t llave;

struct cc *pi;

int *tope;

if((shm1=shmget(ftok(".",'a'),sizeof(struct cc),0600|IPC_CREAT))==-1){

perror("shmget fallo");

exit(1);

}

if((shm2=shmget(ftok(".",'b'),sizeof(int),0600|IPC_CREAT))==-1){

perror("shmget fallo");

exit(1);

}

if((pi=(struct cc *)shmat(shm1, 0,0))==(struct cc*)-1) {

perror("shmat fallo");

exit(1);

}

if((tope=(int *)shmat(shm2, 0,0))==(int *)-1) {

perror("shmat fallo");

exit(1);}

(*tope)=0;

printf("\n Antes de todo tope: %d ", *tope);

llave=ftok(".",'c');

if((semid=initsem(llave))<0) {

perror("initsem fallo");

exit(1);

}

if ((p=fork())>0) {

i=100;

for(;;) {

semopera(semid,MUTEX,-1);

printf("\n tope en el padre : %d ", *tope);

if((*tope)==MAX) {

printf("\n Ya se lleno en el padre");

kill(p,SIGTERM);

wait((int *)0);

semctl(semid,IPC_RMID,0);

shmctl(shm1,IPC_RMID,(struct shmid_ds *)0);

shmctl(shm2,IPC_RMID,(struct shmid_ds *)0);

exit(2);

}

if (*tope>0)

printf("\n 1.Pila anterior: %d",pi->pila[*tope-1]);

pi->pila[*tope]=i++;

printf("\n 1.Pila: %d i=%d ", pi->pila[*tope],i);

(*tope)++;

printf("\n 1.Tope: %d ", *tope);

sleep(4);

semopera(semid,MUTEX,1);

}

}

else if (p==0) {

for(;;) {

semopera(semid,MUTEX,-1);

printf("\n tope en el hijo : %d ", *tope);

if((*tope)==MAX) {

printf("\n Ya se lleno en el hijo ");

kill(getppid(),SIGTERM);

semctl(semid,IPC_RMID,0);

shmctl(shm1,IPC_RMID,(struct shmid_ds *)0);

Page 15: Practica 9 - Weebly · 2018. 9. 11. · Author: Admon Created Date: 11/2/2015 1:51:17 PM

shmctl(shm2,IPC_RMID,(struct shmid_ds *)0);

exit(1);

}

if (*tope > 0)

printf("\n 2.Pila anterior: %d ",pi->pila[*tope-1]);

pi->pila[*tope]=i++;

printf("\n 2.Pila: %d i=%d ", pi->pila[*tope], i);

(*tope)++;

printf("\n 2.Tope: %d ", *tope);

sleep(4);

semopera(semid,MUTEX,1);

}

}

else {

perror("fork fallo");

exit(1);

}

}