2.3. Semáforos en Linux
Texto íntegro de la conversión. Las figuras y la disposición de las notas se pueden consultar en el PDF.
2.3. Semáforos en Linux
Linux ofrece una implementación de semáforos POSIX dentro de su repertorio de llamadas al sistema. En este subapartado presentamos una descripción básica de la interfaz de llamadas al sistema y de cómo utilizarlos dentro de los programas. Aunque la implementación ofrece semáforos con nombre (accesibles a través del sistema de ficheros) y semáforos sin nombre (accesibles por medio de la memoria compartida), en este subapartado nos centraremos en los semáforos sin nombre y que serán utilizados por flujos de ejecución que pertenezcan a un mismo proceso (por lo tanto, comparten el espacio lógico de memoria).
POSIX ofrece el tipo de datos sem_t para declarar variables de tipo semáforo. La interfaz de llamadas al sistema es la siguiente (observad que el parámetro de tipo semáforo se pasa por referencia):
-
int sem_init (sem_t * sem, int pshared, unsigned int value): inicializa el semáforo al valor indicado. En el parámetro pshared especificaremos el valor 0.
-
int sem_wait(sem_t *sem): análoga a la explicada en el subapartado anterior.
-
int sem_post(sem_t *sem): es la equivalente a la operación sem_signal explicada en el subapartado anterior.
Página 23
Las tres llamadas devuelven 0 en caso de poderse realizar correctamente y -1 en caso de error. Un posible error está relacionado con la recepción de señales software (apartado 3.2).
Como ejemplo, la figura 23 muestra un programa10 que emula el funcionamiento de un motor de explosión de cuatro tiempos. Para hacerlo, crea cuatro flujos de ejecución que se sincronizan utilizando semáforos para garantizar que la ordenación de los tiempos sea la correcta (admisión, compresión, explosión y escape). Notad que uno de los semáforos ha sido inicializado en 1 para permitir que el flujo Admisión pueda "arrancar" el motor.
#include <semaphore.h> #include <pthread.h>
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
sem_t sync_tiempo[4];
char *name[4]={"Admisión", "Compresión", "Explosión", "Escape"};
/* Código común para los cuatro tiempos. En función del parámetro "par", cada uno imprimirá un mensaje y determinará qué semáforos utiliza
*/
void *tiempo(void *par)
{ int t = (int) par;
while (1) { if (sem_wait(&sync_tiempo[t]) < 0) error();
printf("%d %s\n", t, name[t]); sleep(rand() % 4); /* Retraso aleatorio */
if (sem_post(&sync_tiempo[(t+1)%4]) < 0) error(); } }
int main()
{ int i; pthread_t th[4];
/* Sincronismo Escape -> Admisión. Inicializado en 1 */ if (sem_init(&sync_tiempo[0], 0, 1) < 0) error();
Notas y pies de figura de la fuente
(10)Para generar el ejecutable correspondiente hay que utilizar la biblioteca de pthreads (parámetro de compilación -pthread).
Página 24
/* Sincronismo Admisión -> Compresión */ if (sem_init(&sync_tiempo[1], 0, 0) < 0) error();
/* Sincronismo Compresión -> Explosión / if (sem_init(&sync_tiempo[2], 0, 0) < 0) error(); / Sincronismo Explosión -> Escape */
if (sem_init(&sync_tiempo[3], 0, 0) < 0) error();
/* Creación de threads */
for (i=0; i<4; i++) if (pthread_create(&th[i], NULL, tiempo, (void*)i) < 0) error();
/* Espera la muerte de los threads */ for (i=0; i<4; i++)
if (pthread_join(th[i], NULL) < 0) error();
return(0);
}
Figura 23. Programa de ejemplo que utiliza semáforos POSIX en Linux.
Ver fragmento extraído sin normalizar
2.3. Semáforos en Linux
Linux ofrece una implementación de semáforos POSIX dentro de su reperto-
rio de llamadas al sistema. En este subapartado presentamos una descripción
básica de la interfaz de llamadas al sistema y de cómo utilizarlos dentro de los
programas. Aunque la implementación ofrece semáforos con nombre (accesi-
bles a través del sistema de ficheros) y semáforos sin nombre (accesibles por
medio de la memoria compartida), en este subapartado nos centraremos en
los semáforos sin nombre y que serán utilizados por flujos de ejecución que
pertenezcan a un mismo proceso (por lo tanto, comparten el espacio lógico
de memoria).
POSIX ofrece el tipo de datos sem_t para declarar variables de tipo semáforo.
La interfaz de llamadas al sistema es la siguiente (observad que el parámetro
de tipo semáforo se pasa por referencia):
• int sem_init (sem_t * sem, int pshared, unsigned int value):
inicializa el semáforo al valor indicado. En el parámetro pshared especifi-
caremos el valor 0.
• int sem_wait(sem_t *sem): análoga a la explicada en el subapartado
anterior.
• int sem_post(sem_t *sem): es la equivalente a la operación sem_signal
explicada en el subapartado anterior.
## Página 23
<!-- source-page: 23 -->
GNUFDL • PID_00214803 23 Comunicación y sincronización
Las tres llamadas devuelven 0 en caso de poderse realizar correctamente y -1
en caso de error. Un posible error está relacionado con la recepción de señales
software (apartado 3.2).
Como ejemplo, la figura 23 muestra un programa10 que emula el funciona- (10)Para generar el ejecutable co-
miento de un motor de explosión de cuatro tiempos. Para hacerlo, crea cuatro rrespondiente hay que utilizar la
biblioteca de pthreads (parámetro
flujos de ejecución que se sincronizan utilizando semáforos para garantizar de compilación -pthread).
que la ordenación de los tiempos sea la correcta (admisión, compresión, ex-
plosión y escape). Notad que uno de los semáforos ha sido inicializado en 1
para permitir que el flujo Admisión pueda "arrancar" el motor.
#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
sem_t sync_tiempo[4];
char *name[4]={"Admisión", "Compresión", "Explosión", "Escape"};
/* Código común para los cuatro tiempos.
En función del parámetro "par", cada uno imprimirá un mensaje
y determinará qué semáforos utiliza
*/
void *tiempo(void *par)
{
int t = (int) par;
while (1) {
if (sem_wait(&sync_tiempo[t]) < 0) error();
printf("%d %s\n", t, name[t]);
sleep(rand() % 4); /* Retraso aleatorio */
if (sem_post(&sync_tiempo[(t+1)%4]) < 0) error();
}
}
int main()
{
int i;
pthread_t th[4];
/* Sincronismo Escape -> Admisión. Inicializado en 1 */
if (sem_init(&sync_tiempo[0], 0, 1) < 0) error();
## Página 24
<!-- source-page: 24 -->
GNUFDL • PID_00214803 24 Comunicación y sincronización
/* Sincronismo Admisión -> Compresión */
if (sem_init(&sync_tiempo[1], 0, 0) < 0) error();
/* Sincronismo Compresión -> Explosión */
if (sem_init(&sync_tiempo[2], 0, 0) < 0) error();
/* Sincronismo Explosión -> Escape */
if (sem_init(&sync_tiempo[3], 0, 0) < 0) error();
/* Creación de threads */
for (i=0; i<4; i++)
if (pthread_create(&th[i], NULL, tiempo, (void*)i) < 0) error();
/* Espera la muerte de los threads */
for (i=0; i<4; i++)
if (pthread_join(th[i], NULL) < 0) error();
return(0);
}
Figura 23. Programa de ejemplo que utiliza semáforos POSIX en Linux.