Éstas son colas de mensajes, semáforos y memoria compartida. Las colas de mensajes serán omitidas aquí pues sus servicios pueden ser cubiertos por las pipes.
Como en el caso de los FIFOS, estos mecanismos se pueden aplicar a procesos que no están vinculados, pero residen en la misma máquina.
Cada uno de estos mecanismos de comunicación son referidos por el kernel vía un identificador entero no negativo, el cual cumple un rol similar al del archivo en las FIFOs.
El identificador es creado y retornado cuando el mecanismo para IPC (ya sea semáforo, memoria compartida) es creado y corresponde a un número que crece hasta alcanzar un valor máximo y luego vuelve a cero. El identificador es un nombre interno para el objeto IPC. Los proecesos requieren un mecanismo externo para enterarse del objeto IPC que desena manipular. Para ello, cada objeto IPC está asociado a una clave externa que actúa como nombre externo del objeto IPC.
Esta clave (key) debe ser única dentro de la máquina. Si no es así, la estructura para la comunicación entre procesos no es creada (arroja un error).
La clave (key) puede ser obtenida de tres formas:
Para crear una nueva estructura IPC, el servidor llama a una de las funciones "get". Ésta requiere una key (IPC_PRIVATE, un valor fijo, o el retornado por ftok) y en el argumento flag se debe activar el bit IPC_CREATE. Activando el bit IPC_EXCL se puede asegurar que la estructura es nueva (de no serlo se retorna un error).El servidor crea una nueva estructura especificando una clave de IPC_PRIVATE. El procedimiento creador retorna un identificador para la nueva estructura. El problema es que ésta debe ser comunicada al proceso cliente de alguna manera. Por ejemplo, a través de un archivo. Otra forma es que el servidor y cliente se pongan de acuerdo en una clave. El problema es que ésta puede coincidir con otra ya existente. El servidor y el cliente pueden convenir un path y un identificador de proyecto ( 0<= project ID <=255) y llamar a la función ftok, la cual convierte estos dos valores en una clave.
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char * path, int projectID); /* key_t es generalmente un long int */
El cliente accede a la estructura creada por el servidor llamando a la función get con la misma clave y el bit del flag IPC_CREATE desactivado.
Algunas estructuras de datos son creadas globalmente en el sistema, el cual no maneja un contador de referencias. La estructura permanece en el sistema hasta que es removida por un proceso o la máquina es "rebooted". (Parecido a procesos zombies).
int semget(key_t key, int nsems, int semflg);
Para remover un semáforo o
hacer otra tareas de control
int semctl( int semid, int semnum,
int cmd, union semun arg);
El parámetro cmd puede adoptar los siguientes
valores entre otros:
IPC_STAT: para leer el estado del semáforo.
IPC_SET: permite cambiar los permisos de acceso del
semáforo.
IPC_RMID: Permite remover el semáforo.
Para operar el semáforo:
int semop (int semid, struct sembuf
*ops, size_t nops);
struct sembuf {
ushort sem_num;
short sem_op;
short sem_flg;
};
En general estas funciones no son amigables para operar con semáforos debido a:
Creación de una región de memoria compartida
#include <sys/types.h>Con esta llamada se crea una estructura de control asociada a esta memoria compartida.
#include <sys/ipc.h>
#include <sys/shm.h>int shmget (key_t key, int size, int flag);
Esta estructura se puede manipular a través
de la función shmctl()
shmctl ( int
shmid, int cmd, struct shmid_ds * buf );
Uno de los comandos permite remover la región de memoria compartida.
Para hacer uso de la memoria compartida los procesos
deben ligar (attach) el segmento de memoria compartida. Esto se hace
con
la función shmat()
void * shmat (int shmid, void
*shmaddr, int shmflg);
shmaddr es la dirección a la cual la memoria
debe ser ligada. Se recomienda especificar 0 (y el sistema elige la
mejor dirección).
Si shmflg contiene el flag SHM_RDONLY, la memoria es de
sólo lectura, en otro caso es lectura y escritura.
Para desligar (detach) la memoria compartida:
int shmdt( void *shmaddr);
Donde shmaddr es el valor retornado por shmat().
Ejemplo: Productor consumidor usando memoria compartida. Un programa actúa como servidor y otro como cliente. El servidor lee información desde la entrada estándar y la transfiere a la memoria compartida. El cliente la lee desde la memoria compartida y la escribe en la salida estándar.
La memoria compartida creada permanece en el sistema hasta que esta sea removida. Es así como podemos crear un programa que escriba en memoria y otro que más tarde la lea.
En este caso no hemos usado la versión amigable para manejo de semáforo
pues no es requerida. Una versión más completa de este programa, es
decir que permita su ejecución conjunta o separada, no puede usar las
funciones amigables para semáforos porque éstas remueven el semáforo
cuando el proceso termina.
Otros ejemplos de uso de memoria compartida y semáforos.