Semáforos Comunicación entre procesos Sistemas Operativos M.C. José Alberto Morales Mancilla
Semáforos
Comunicación entre procesos
Sistemas Operativos M.C. José Alberto Morales Mancilla
Comunicación entre procesos (IPC)
Los procesos en UNIX no comparten memoria, ni siquiera los padres con los hijos. Por tanto hay que establecer un mecanismo, en caso de que se quiera comunicar información entre procesos concurrentes.
Comunicación entre procesos (IPC)
El sistema operativo UNIX define tres clases de herramientas de comunicación entre procesos IPC:
• Los semáforos.• La memoria compartida.• Los mensajes.
Comunicación entre procesos (IPC)
Existen funciones shmget y msgget para crear o enlazarse a un segmento de memoria compartida o a una cola de mensajes respectivamente.Para alterar las propiedades de estos IPC´s incluyendo su borrado están las funciones shmctl y msgctl.
Comunicación entre procesos
Para enviar o recibir mensajes, se utilizan las funciones msgsnd y msgcrv.
Semáforos
¿Qué es un semáforo para UNIX?
Es una variable entera con operaciones atómicas de inicialización, de incremento y decremento con bloqueo.
Semáforos
UNIX define tres operaciones fundamentales sobre semáforos:
• semget crea o toma el control de un semáforo.• semctl operaciones de lectura y escritura del
estado del semáforo. Destrucción del semáforo.• semop operaciones de incremento y decremento
con bloqueo. Operaciones P y V sobre el semáforo.
Semáforos
Como el lenguaje C no tiene ningún tipo “semáforo” predefinido, si se desea utilizar semáforos se tienen que crear mediante una llamada al sistema semget. Esta llamada permite crear un conjunto de semáforos en lugar de uno solo.Al crear un semáforo se devuelve un número identificador.
Semáforos
La función semget nos permite además abrir un semáforo que ya esté creado. Así por ejemplo si un proceso crea un semáforo, otros procesos pueden sincronizarse con el usando el semáforo con semget.
Para darle un valor inicial al semáforo se utiliza la función semctl.
Semget
Mediante semget vamos a poder crear o acceder a un conjunto de semáforos unidos bajo un identificador común. Semget tiene la siguiente declaración:#include <sys/types.h>#include<sys/ipc.h>#include <sys/sem.h>int semget(key_t, int nsems, int semflg);
Semget
Si la llamada funciona correctamente, devolverá un identificador con el que podemos acceder a los semáforos en sucesivas llamadas. Si algo falla, semget devolverá el valor -1 y en errno estará el código de error producido.
Semget
•Key es la llave que indica a qué grupo de semáforos queremos acceder. Esta llave puede crearse mediante una llamada a ftok. Si key toma el valor IPC_PRIVATE, la llamada crea un nuevo identificador sujeto a la disponibilidad de entradas libres en la tabla que gestiona el núcleo para los semáforos.
Semget
•Nsems es el total de semáforos que van a estar agrupados por el identificador devuelto por semget.
•Semflg es una máscara de bits que indican el modo de adquisición del identificador. Si el bit IPC_CREAT está activo, la facilidad IPC se creará en el supuesto de que otro proceso no la haya creado ya.
Ejemploint llave, semid;…If ((llave = ftok (“auxiliar”,’K’)) == (key_t)-1){ /* Error al crear la llave */}if (( semid = semget (llave, 4, IPC_CREAT | 0600)) == -1){ /* Error al crear el identificador */}
Semáforo
semctl también se utiliza para destruir el semáforo.
UNIX no ofrece las funciones clásicas P y V o equivalentes sino que dispone de una función semop que permite realizar una gama de operaciones incluyendo las P y V.
Llamadas al sistema para semáforos
Para el uso correcto de todas las funciones, se debe incluir el archivo de cabecera <sys/sem.h>
Las tres funciones devuelven -1 si algo ha salido mal y en tal caso la variable errno informa el tipo de error.
Apertura o creación de un semáforo.
semget devuelve el identificador del semáforo correspondiente a la clave key. Puede ser un semáforo ya existente o bien semget crea uno nuevo.Sintaxis:
int semget (key_t key, int nsems, int semflg);
Apertura o creación de un semáforo
1. key vale IPC_PRIVATE. Este valor obliga a semget a crear un nuevo y único identificador, nunca devuelto por llamadas anteriores a semget hasta que sea liberado con semctl.
2. Key no está asociada a ningún semáforo existente y se cumple que (semflg & IPC_CREAT) es cierto.A un semáforo puede accederse siempre que se tengan los permisos adecuados.
Apertura o creación de un semáforo.
nsems significa cuántos semáforos tiene el conjunto creado.Los 9 bits inferiores de semflg contienen los permisos estilo UNIX de acceso al semáforo (usuario, grupo, otros).
Apertura o creación de un semáforo
semflg es una máscara que puede contener IPC_CREAT o IPC_EXCL, que hace crear al semáforo, pero fracasando si ya existía.Ejemplo:
int semid=semget(IPC_PRIVATE,1,IPC_CREAT|0744);
Operaciones de control sobre semáforos
semctl es una función para realizar operaciones sobre semáforos:
int semctl (int semid, int semnum, int cmd..);
semid es un identificador de semáforo devuelto por semget y semnun es el semáforo del conjunto sobre el que se quiere trabajar.
Operaciones de control sobre semáforos.
cmd es la operación aplicada, a continuación puede aparecer un parámetro opcional según la operación definida por cmd.Las operaciones que nos interesan son:
• GETVAL semctl retorna el valor actual del semáforo.
• SETVAL se modifica el valor del semáforo (un cuarto parámetro entero da el nuevo valor).
Operaciones de control sobre semáforos
• IPC_RMID destruye el semáforo.
Ejemplos:valor = semctl(semid, semnum, GETVAL);
semctl(semid,semnum, SETVAL, nuevo valor);
Operaciones sobre semáforos.
semop realiza atómicamente un conjunto de operaciones sobre semáforos, pudiendo bloquear al proceso llamador.
int semop(int semid, struct sembuf* sops, unsigned nsops);
semid es el identificador del semáforo y sops es un apuntador a un vector de operaciones, nsops indica el número de operaciones solicitadas.
Operaciones sobre semáforos.
La estructura sembuf tiene estos campos:struct sembuf{ unsigned short sem_num; //número de semáforo
dentro del conjunto short sem_op; //clase de operación según sea <0,
>0, ==0 short sem_flg; //modificadores de operación};
Operaciones P y V. Semop
•Sem_num es el número del semáforo y se utiliza como índice para acceder a él. Su valor está en un rango 0..N-1, donde N es el total de semáforos que hay agrupados bajo el identificador.
Operaciones P y V. Semop•Sem_op es la operación a realizar sobre
el semáforo especificado en sem_num. Si sem_op es negativo, el valor del semáforo se decrementará, lo que equivale a una operación P. Si sem_op es positivo, el valor del semáforo se incrementará, lo que equivale a una operación V. Si sem_op vale 0, el valor del semáforo no sufre ninguna alteración.
Ejemplostruct sembuf operación;int semid;semid=semget(IPC_PRIVATE,3,IPC_CREAT|0600);semctl(semid,0,SETVAL,1);semctl(semid,1,SETVAL,0);semctl(semid,2,SETVAL,0);operación.sem_num=1; /*cerramos el semaforo */operación.sem_op=-1; //operación Psemop(semid,&operación,1);operación.sem_num=0;/*abrimos el semaforo*/operación.sem_op=1;
Destrucción del semáforo
semctl(semid,0,IPC_RMID,0);
Ejemplo#include <stdio.h#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#define SEM_HIJO 0#define SEM_PADRE 1
void main(void) { int i=30, semid, pid; char argv[10]; struct sembuf operación; key_t llave; printf(“Dame el identificador “); scanf (“%s”,&argv); printf(“\n %s”, argv); llave = ftok (argv,’K’);
Creación de semáforos
if (( semid = semget (llave, 2, IPC_CREAT | 0600 )) == -1)
{perror (“ semget “);exit (-1);
}
Inicialización de semáforos
/* Cerrar el semáforo del proceso hijo */
semctl ( semid, SEM_HIJO, SET_VAL, 0);
/* abrir el semáforo del proceso padre */semctl ( semid, SEM_PADRE, SET_VAL, 1);
Creación del proceso hijo
if (( pid = fork()) == -1) {perror (“fork” );exit (-1);
}else if (pid == 0) {
while (i) { operación.sem_num = SEM_HIJO; operación.sem_op = -1; operación.sem_flg = 0; semop (semid, &operación, 1); printf (“proceso hijo %d\n”, i--);/*abrir proceso padre */ operación.sem_num = SEM_PADRE;
operación.sem_op = 1; semop (semid, &operación, 1); } semctl (semid, 0, IPC_RMID,0);
}
Ejecución del proceso padre
else {
while (i) {operación.sem_num = SEM_PADRE;operación.sem_op = -1;semop ( semid, &operación, 1);printf(“ proceso padre %d\n”, i--);/* abrir proceso hijo */operación.sem_num = SEM_HIJO;operación.sem_op = 1;semop ( semid, &operación, 1);
} semctl (semid,0,IPC_RMID,0);
}}