You are on page 1of 11

Prctica 3.

Paquete de comunicacin entre procesos IPC


Los procesos estn dotados para comunicarse con otros procesos mediante operaciones de entrada y salida para acceder a archivos y dispositivos y operaciones de comunicacin entre procesos dentro del mismo computador con tuberas y en computadoras diferentes con sockets El elemento clave es el descriptor de cada objeto. El descriptor de archivos o bloque de control de archivos es un bloque de control que contiene informacin que el sistema necesita para administrar un archivo. Es una estructura muy dependiente del sistema y puede incluir la siguiente informacin: Nombre simblico del archivo. Localizacin del archivo en el almacenamiento secundario. Organizacin del archivo (mtodo de organizacin y acceso). Tipo de dispositivo. Datos de control de acceso. Tipo (archivo de datos, programa objeto, programa fuente, etc.). Disposicin (permanente contra temporal). Fecha y tiempo de creacin. Fecha de destruccin. Fecha de la ltima modificacin. Suma de las actividades de acceso (nmero de lecturas, por ejemplo).

Los descriptores de archivos suelen mantenerse en el almacenamiento secundario y se pasan al almacenamiento primario al abrir el archivo. El descriptor de archivos es controlado por el sistema de archivos, el usuario puede no hacer referencia directa a l. Los procesos no utilizan directamente los objetos de comunicacin ni sus descriptores, lo hacen mediante: Llamadas al sistema de apertura o creacin Llamadas al sistema de escritura y lectura Llamadas al sistema de cierre o eliminacin Llamadas al sistema para obtener informacin

El paquete de comunicacin entre procesos (IPC) del UNIX System V se compone de tres mecanismos: Semforos para sincronizar procesos Memoria compartida para compartir el espacio de direcciones virtuales de los procesos Colas de mensaje para intercambiar datos con un formato determinado entre procesos

Las estructuras IPC estn en el ncleo, como los pipes, y no en el sistema de archivos, como las MKFIFO. Cada mecanismo IPC posee un identificador nico. Al crear un IPC es necesario especificar una clave de tipo key_t, que el ncleo usa para generar el identificador del IPC (key_t es un entero). En la cabecera <sys/types.h> se define el tipo key_t, que suele ser un entero de 32 bits. La funcin ftok devuelve una llave basada en pathname y id. #include <sys/types.h> #include <sys/ipc.h> key_t ftok (char *pathname, int id); 1

pathname es un nombre de archivo que debe existir en el sistema, y al cual debe poder acceder el proceso que llama a ftok id es un entero que identifica al proyecto ftok devolver la misma llave para rutas enlazadas a un mismo archivo, siempre que se utilice el mismo valor para id. Para el mismo archivo, ftok devolver diferentes llaves para distintos valores de id

Si el archivo no es accesible para el proceso, bien porque no existe, bien porque sus permisos lo impiden, ftok devolver el valor -1, que indica que se ha producido un error en la creacin de la llave. Ejemplo: El siguiente trozo de cdigo muestra el uso de la funcin ftok: key_t llave; llave = ftok("prueba", 1); if (llave == (key_t) -1) { /* Error al crear la llave. Tratamiento del error */ } Diferentes llamadas a la funcin de creacin de un IPC con la misma clave devuelven el mismo identificador, lo que permite compartir un IPC entre procesos Cmo asegurar que todos los procesos que quieran usar la misma estructura IPC utilicen la misma clave? En caso de procesos creados con fork estos comparten el identificador Si el proceso hijo realiza un exec, se puede pasar el identificador mediante un parmetro al exec Un proceso crea el IPC y guarda la clave en un archivo accesible a los otros procesos Poner la clave en un archivo cabecera (.h) comn Apoyarse en la funcin de la biblioteca de C ftok

Para tener una administracin de identificadores creados por los mecanimos IPC se tienen los comandos del Shell ipcs e ipcrm: ipcs: mostrar informacin (-q, -m, -s) ipcrm: eliminar mecanismos IPC (-q, -m, -s)

Las desventajas del IPC del Unix System V son: Tiene una interfaz de programacin compleja No se mantiene contador del nmero de procesos que est usando una estructura y por lo tanto no hay un mtodo automtico para reclamar estructuras IPC abandonadas

Si un proceso crea y usa una estructura y termina sin eliminarla apropiadamente, la estructura permanece hasta que se reinicie el sistema, se elimine especficamente con el comando ipcrm u otro proceso la elimine

Semforos Un semforo es un mecanismo de sincronizacin para prevenir una colisin que se produce cuando dos o ms procesos solicitan simultneamente un recurso que se debe compartir. Dijkstra los crea en 1965 y los define como un tipo abstracto de datos que admite dos operaciones: P (espera o wait) decrementa o proberen (obtener el recurso o bloquearlo) V (seal o signal) incrementa o verhogen (liberar el recurso)

Importante: las operaciones P y V son Atmicas Para la creacin de un semforo se tiene la llamada semget: #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget (key_t key, int nsems, int semflg); key es la clave que identifica al grupo de semforos nsems es el nmero de semforos a crear semflg es una mscara de bits (IPC_CREAT, IPC_EXCL, permisos) Ejemplo: int semid=semget(IPC_PRIVATE, 1, IPC_CREATE | 0600)

La llamada semctl nos da acceso a la informacin administrativa y de control que dispone el ncleo de un semforo. #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semctl (int semid, int semnum, int cmd, union semun arg); semnum es el numero del semforo del conjunto en con que se quiere operar (entre 0 y nsems-1) cmd indica la operacin a realizar. Segn el valor de cmd, arg contendr otras opciones. Las opciones ms interesantes son: GETVAL, retorna el valor actual del semforo SETVAL, modifica el valor del semforo (un cuarto parmetro entero especfico el nuevo valor) IPC_RMID, destruye el semforo La llamada semop nos permite realizar operaciones atmicas sobre el conjunto de semforos. #include <sys/types.h> #include <sys/ipc.h> 3

#include <sys/sem.h> int semop (int semid, struct sembuf *sops, int nsops); semid identifica al grupo de semforos sobre los que se va a realizar la operacin. sops es un puntero a un array de estructuras que indican las operaciones que se realizarn sobre los semforos. nsops es el nmero de elementos del array sops. Las operaciones se especifican mediante una estructura de tipo sembuf. struct sembuf { ushort sem_num; /* nmero del semforo*/ short sem_op; /*operacin (inc. o dec.)*/ short sem_flg; /*mscara de bits*/ } semop >0 => incremento y desbloqueo semop <0 => bloqueo y/o disminucin segn sem_flg (IPC_WAIT, IPC_NOWAIT, SEM_UNDO) semop =0 => el proceso se bloquea hasta que el semforo sea 0 (a menos que se especifique IPC_NOWAIT en sem_flg) Programa3a.c Edite, compile, ejecute, analice y comente con su equipo que sucede en el siguiente programa. #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> #include<stdio.h> #include<stdlib.h> #define PERMISOS 0644 int crea_sem(key_t llave,int valor_inicial) { int semid=semget(llave,1,IPC_CREAT/PERMISOS); if(semid==-1) { return -1; } semctl(semid,0,SETVAL,valor_inicial); return semid; } void down(int semid) { struct sembuf op_p[]={0,-1,0}; semop(semid,op_p,1); } void up(int semid) 4

{ struct sembuf op_v[]={0,1,0}; semop(semid,op_v,1); } main() { int i=10,mutex; pid_t pid; key_t llave; llave=ftok("llave",'k'); mutex=crea_sem(llave,1); pid=fork(); if(pid==0) { while(i) { printf("Hijo con pid %d...Fuera de la region critica\n",getpid()); down(mutex); printf("Hijo en la region critica %d...\n",i--); sleep(i); up(mutex); } } else { while(i) { printf("Padre con pid %d...Fuera de la region critica \n",getpid()); down(mutex); printf("Padre en la regin critica %d...\n",i--); sleep(i); up(mutex); } } } Programa3b.c Elabore un programa que tenga una variable con un valor inicial de cero. Posteriormente se deben crear dos hilos independientes, uno de ellos incrementa permanentemente la variable en uno y el otro la disminuya en uno. Despus de n segundos el proceso debe imprimir el valor final de la variable y terminar. El nmero de segundos que el proceso padre espera, se debe pasar en la lnea de comandos. Sincronice los hilos mediante el uso de semforos. (30% de la calificacin de la prctica) Memoria compartida La forma ms rpida de comunicar dos procesos es hacer que compartan una zona de memoria. La memoria convencional que puede direccionar un proceso es local al mismo, y cualquier intento de acceso desde otro proceso provocar una violacin de segmento. UNIX System V proporciona un sistema de memoria compartida entre varios procesos. Para trabajar con memoria compartida es necesario crear un vnculo entre la memoria local del proceso y el segmento compartido. El proceso 5

que vincula un segmento de memoria compartida cree estar trabajando con ella como si fuera cierta rea de memoria local. Para crear una zona de memoria compartida usamos la llamada shmget: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget (key_t key, int size, int shmflg); Donde: key es la clave que identifica al segmento de memoria (IPC_PRIVATE o una clave devuelta por ftok). size especifica el tamao del segmento (ser redondeado al valor de PAGE_SIZE). shmflg es una mscara de bits (IPC_CREAT, IPC_EXCL, permisos).

Antes de usar la memoria compartida, tenemos que asignarle un espacio de direcciones virtuales de nuestro proceso; es lo que se conoce como atarse al segmento de memoria compartida. Al terminar de usar el segmento de memoria, debemos desatarnos de l. #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> char *shmat (int shmid, char *shmaddr, int shmflg); int shmdt (char *shmaddr); Donde: shmid es el identificador del segmento. shmaddr es la direccin virtual donde queremos que empiece la zona de memoria compartida (cuando toma el valor 0, es el ncleo el que elige la direccin virtual de inicio) shmflg es una mscara de bits que indica la forma de acceso (SHM_RDONLY). Para controlar una zona de memoria compartida usamos la llamada shmctl: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmctl (int shmid, int cmd, struct shmid_ds *buf); Algunas opciones son: IPC_STAT: lee la estructura de control asociada a shmid y la deposita en 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. El segmento desaparecer cuando el ltimo proceso que lo utiliza notifique su desconexin del segmento. SHM_LOCK: bloquea la zona de memoria compartida (slo superusuario). SHM_UNLOCK: desbloquea la regin de memoria compartida (slo superusuario). 6

Programa3c.c Edite, compile, ejecute, analice y comente con su equipo lo que sucede en el siguiente programa. #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> main() { int shmid, i; int *variable; key_t llave; pid_t pid; llave=ftok("Prueba",'k'); shmid=shmget(llave,sizeof(int),IPC_CREAT|0600); variable=shmat(shmid,0,0); *variable=10; printf("\nLa variable vale %d\n",*variable); if((pid=fork())==0) { (*variable)--; exit(0); } else { wait(0); printf("La variable ahora vale:%d\n",*variable); } shmdt(&variable); shmctl(shmid,IPC_RMID,0); } Programa3d.c. Realizar un programa que utilice memoria compartida donde un proceso padre crea un arreglo con tipos de dato float de 10 posiciones y lo comparte con un proceso hijo. El proceso hijo genera 10 nmeros aleatorios de tipo float y los guarda en el arreglo compartido. Al final el proceso padre muestra los nmeros que grab el proceso hijo en el arreglo. (30% de la calificacin de la prctica) Colas de mensajes Son listas de mensajes gestionadas por el ncleo. La comunicacin tiene lugar entre procesos lanzados en la misma mquina. Pueden existir mltiples procesos lectores y escritores. La sincronizacin es responsabilidad del ncleo. Los mensajes tienen este tipo: Tipo del mensaje (long) DATOS del mensaje

Los mensajes se pueden extraer en orden FIFO, pero tambin en otro orden. El receptor puede esperar: 7

El siguiente mensaje (orden FIFO) El siguiente mensaje de cierto tipo

El ncleo impone lmites mximos a el nmero de bytes de un mensaje y el nmero de bytes en una cola as como el nmero de colas en el sistema y el nmero de mensajes en el sistema. Para crear la cola de mensajes se utiliza msgget: int msgget(key_t key, int msgflg); El primer parmetro, key, es un nmero que usan los diferentes procesos para acceder a la misma cola de mensajes. El segundo parmetro, msgflag, consiste en los nueve permisos asociados a la cola. El valor IPC_CREAT se puede utilizar, mediante la operacin OR con los permisos asociados, para crear una nueva cola. Si la cola ya existe, no se crea nuevamente. Para controlar una cola de mensajes usamos la llamada msgctl: int msgctl(int msqid, int cmd, struct msqid_ds *buf); Donde msqid es un identificador de cola devuelto por msgget y cmd es una accin a tomar. Por ejemplo, IPC_RMID permite eliminar la cola de mensajes. El ltimo parmetro, es un puntero a una estructura que permite almacenar valores tales como los permisos y usuarios asociados a la cola. Otras opciones son: IPC_STAT: devuelve la estructura de control asociada a la cola de mensajes. IPC_SET: establece algunos valores en la estructura de control. IPC_RMID: elimina la cola de mensajes del sistema de forma inmediata. Para escribir y leer mensajes usamos, respectivamente, las llamadas msgsnd y msgrcv int msgsnd(int msqid, void *msg_ptr, size_t msg_sz, int msgflg); El primer parmetro, msqid, es el identificador de la cola devuelto por la funcin msgget. El segundo parmetro es un puntero a la estructura del mensaje, la cual debe iniciar con un entero largo. As, se sugiere que la estructura del mensaje sea algo como: struct mensaje { long int tipo; char texto[tamao]; }; donde tipo indica el tipo de mensaje que se desea enviar. El tercer parmetro es el tamao del mensaje, mientras que el cuarto parmetro indica la accin a ejecutar si la cola est llena: bloquearse o continuar. int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg); 8

El primer parmetro, msqid, es el identificador de la cola de mensajes devuelto por msgget. El segundo parmetro, es el puntero a la estructura del mensaje, la cual debe empezar con un entero largo que almacenar el tipo de mensaje. El tercer parmetro, msg_sz, es el tamao del mensaje apuntado por msg_ptr. El cuarto parmetro, msgtype, es un entero largo que permite elegir el tipo de mensaje a retirar de la cola. Si vale 0, se retira el primer mensaje de la cola; si tiene un valor mayor a 0, se retira el primer mensaje con el mismo tipo asociado. El quinto parmetro, msg_flg, indica lo que se hace si no hay mensaje del tipo buscado en la cola. Es decir, bloquearse hasta que llegue un mensaje como el buscado o continuar. msgrcv devuelve el nmero de bytes retirados de la cola -1 si hubo algn error. El campo msgflg tiene distintos significados segn sea la llamada msgsnd o msgrcv Para la llamada msgsnd, si la cola est llena (el nmero de mensajes en la cola es igual al lmite del sistema o el nmero de bytes en la cola es igual al lmite del sistema): Si IPC_NOWAIT est activo, msgsnd retorna inmediatamente el error EAGAIN. Si IPC_NOWAIT no est activo, el proceso que llama a msgsnd se bloquea hasta que haya espacio para el mensaje o la cola sea eliminada del sistema, en este devuelve EIDRM. Tambin se puede dar el caso de que se reciba una seal y se vuelva del manejador de seal y para esto se devuelve EINTR. Para la llamada msgrcv, si la cola est vaca: Si IPC_NOWAIT est activo, msgrcv retorna inmediatamente el error EAGAIN. Si IPC_NOWAIT no est activo, el proceso que llama a msgrcv se bloquea hasta que haya un mensaje del tipo deseado. Programa3e.c Edite, compile, ejecute, analice y comente con su equipo lo que sucede en el siguiente programa.

#include<sys/types.h> #include<stdio.h> #include<stdlib.h> #include<sys/ipc.h> #include<sys/msg.h> main() { int msqid; struct { long tipo; char cadena[20]; }mensaje; int longitud =sizeof(mensaje)-sizeof(mensaje.tipo); pid_t pid; pid=fork(); key_t llave; llave=ftok("Prueba",'K'); msqid=msgget(llave,IPC_CREAT|0666); 9

if(pid==0) { struct { long tipo; char cadena[20]; }mensaje_recibido; while(1) { msgrcv(msqid,&mensaje_recibido,longitud,1,0); printf("\nEste mensaje me lo manda el padre %s",mensaje_recibido.cadena); } } else { mensaje.tipo=1; while(1) { printf("\nEscribe el mensaje que se mandara: "); fgets(mensaje.cadena,sizeof(mensaje.cadena),stdin); msgsnd(msqid,&mensaje,longitud,0); } } } Programa3f.c Edite, compile, ejecute, analice y comente con su equipo lo que sucede en el siguiente programa.. Este programa est en relacin con el Programa3e.c #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct mensaje { long int tipo; char texto[256]; }; int main() { struct mensaje datos; int msgid; char bufer[256]; msgid=msgget((key_t)1234,0666|IPC_CREAT); while(strncmp(bufer,"fin",3)!=0) { printf("Escribe algo ... "); fgets(bufer,256,stdin); datos.tipo=1; 10

strcpy(datos.texto,bufer); msgsnd(msgid,(void*)&datos, 256,0); } exit(0); } Programa3g.c Edite, compile, ejecute, analice y comente con su equipo lo que sucede en el siguiente programa.

#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct mensaje { long int tipo; char texto[256]; }; int main() { struct mensaje datos; int msgid; long int tipo=0; msgid=msgget((key_t)1234,0666|IPC_CREAT); while(strncmp(datos.texto,"fin",3)!=0) { msgrcv(msgid,(void *)&datos,256,tipo,0); printf("Escribiste: %s", datos.texto); } msgctl(msgid,IPC_RMID,0); exit(0); } Programa3h.c Crear una comunicacin bidireccional (chat) entre dos procesos que no tengan ancestros en comn por medio de colas de mensajes. (40% de la calificacin de la prctica)

11