Objetivos
- Conocer las funciones de Unix para sincronización de procesos
- Semáforos
- Regiones de memoria compartida entre procesos
- Intercambio de mensajes
- Crear clases de C++ para encapsular los llamados al sistema (system calls)
- Semáforos: semget, semctl, semop
- Regiones de memoria: shmget, shmctl, shmat, shmdt
- Intercambio de mensajes: msgget, msgctl, msgsnd, msgrcv
- Crear programas que utilicen varios procesos y poder sincronizarlos
Requisitos
- Comprender de manera básica la sincronización de procesos
- Entender el funcionamiento básico de las funciones de IPC
- Compilador de C++ instalado
Notas
- Vamos a construir una serie de programas en C++ que encapsulen algunas de las funciones que propone UNIX para la sincronización de procesos, entre ellas semáforos, paso de mensajes a través de buzones, memoria compartida. La idea de estas nuevas clases es poder ocultar al usuario común, eventualmente ustedes mismos, la complejidad de los llamados al sistema (system call) que ofrece UNIX y establecer una interfaz agradable
- Para que el compilador entienda que se trata de un programa en C++ la extension del archivo debe ser "cc", "c++" o "cpp". Si quiere utilizar otra extensión para el archivo debe compilarlo llamando directamente al compilador de C++: "g++"
- Recuerde que puede hacer uso de los programas que ha desarrollado en los laboratorios anteriores
- Tenga en cuenta que puede utilizar los comands "ipcs" e "ipcrm" para listar todos los recursos de IPC definidos en la máquina que está utilizando
- Todas estas clases pueden ser utilizadas en su segunda tarea programada
- Anote en su informe todas las observaciones que considere pertinentes durante el desarrollo de este laboratorio
Notas de Unix
- Recuerde también que los llamados al sistema (system calls) en la mayoría de los casos van a devolver -1 si ocurrió algún error, sus programas deben de controlar todas las situaciones de error posibles (NO utilizar el estilo de programación de pantallas azules)
- Puede utilizar las funciones y variables definidas en "<errno.h>" (la variable errno (int) contiene el número del error que ocurrió y la función "perror( mensaje );" que despliega una descripción del último error que sucedió.
- Al final de la descripción disponible en el manual (man) se describen los errores de los llamados al sistema y es fácil encontrar la solución, una vez que se entiende el error. Por ello es recomendable que, si tiene un error busquen la descripción en el man.
Procedimiento
- Lo primero que debe hacer es utilizar el comando "man" en una terminal para encontrar una descripción de lo que se puede hacer con semáforos. Por ejemplo, puede utilizar el comando "man" con la función "semget", "semctl" o "semop".
- Cree una nueva clase de C++ que encapsule la funcionalidad de los semáforos
que ofrece UNIX, brindando al menos los siguientes métodos: un constructor, un
destructor, un método Signal (o V) y un método Wait (o P). Recuerde que puede utilizar el comando man para asegurarse de que los llamados al sistema poseen los parámetros adecuados. Recuerde que algunos de los parámetros necesarios pueden ser declarados como miembros privados de la clase.
#define KEY 0xA12345 // Valor de la llave del recurso
class Semaforo {
Semaforo( int ValorInicial = 0 );
~Semaforo();
int Signal(); // Puede llamarse V
int Wait(); // Puede llamarse P
private:
int id; // Identificador del semaforo
};
- Construya un programa que utilice la clase creada en el punto anterior para sincronizar dos procesos (fork), compruebe que su implantación de la clase es funcional y cumple con lo visto en clase para sincronizar procesos. Para hacer que el padre espere a que el hijo termine se puede utilizar el llamado al sistema "wait", utilice man para ver su descripción, o puede leer algún valor del teclado.
- Haga que su programa del punto anterior se "caiga" sin liberar los recursos de manera que pueda listarlos con el comando "ipcs"
- Puede hacer que el programa se "caiga" (termine) presionando las teclas "Ctrl" y "C" simultáneamente"
- También puede quitar el comentario del "printf" y volver a compilar, el programa va a terminar por un acceso ilegal a memoria
- En la terminal, liste los recursos empleados utilizando "ipcs"
- Trate de remover el recurso creado utilizando el comando "ipcrm"
- Repita los pasos anteriores a fin de crear una clase para el paso de mensajes.
#define KEY 0xA12345 // Valor de la llave del recurso
class Buzon {
Buzon();
~Buzon();
int Enviar( char * mensaje );
int Recibir( char *mensaje, int len ); // len es el tamaño máximo que soporte la variable mensaje
private:
int id; // Identificador del buzon
};
- Para este caso de los mensajes, también haga que el programa se "caiga" antes de enviar un mensaje, luego hágalo cuando se ha enviado un mensaje, anote las diferencias en su informe.
- Utilice los llamados para manipular memoria compartida y construya un programa que cree un segmento de memoria compartida entre dos procesos (padre e hijo). Haga que el padre escriba una tira de caracteres en el área compartida, luego despliegue esta tira en el hijo. No es necesario crear una clase para esto, pero si usted lo considera conveniente hágalo.
- Ejemplos adicionales
- Primero corra el programa para enviar, luego el de recibir
- Envia sin clases Envia
- Recibe sin clases Recibe
- Envia con clases Envia
- Recibe con clases Recibe