Ejemplos java y C/linux

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace https://old.chuidiang.org

Semáforos en C para Linux

A veces es necesario que dos o más procesos o hilos (threads) accedan a un recurso común (escribir en un mismo fichero, leer la misma zona de memoria, escribir en la misma pantalla, etc). El problema es que si lo hacen simultáneamente y de forma incontrolada, pueden "machacar" el uno la operación del otro (y dejar el fichero o la memoria con un contenido inservible o la pantalla ilegible).

Para evitar este problema, están los semáforos. Un semáforo da acceso al recurso a uno de los procesos y se lo niega a los demás mientras el primero no termine. Los semáforos, junto con la memoria compartida y las colas de mensajes, son los recursos compartidos que suministra UNIX para comunicación entre procesos.

El funcionamiento del semáforo es como el de una variable contador. Imaginemos que el semáforo controla un fichero y que inicialmente tiene el valor 1 (está "verde"). Cuando un proceso quiere acceder al fichero, primero debe decrementar el semáforo. El contador queda a 0 y como no es negativo, deja que el proceso siga su ejecución y, por tanto, acceda al fichero.

Ahora un segundo proceso lo intenta y para ello también decrementa el contador. Esta vez el contador se pone a -1 y como es negativo, el semáforo se encarga de que el proceso quede "bloqueado" y "dormido" en una cola de espera. Este segundo proceso no continuará por tanto su ejecución y no accederá al fichero.

Supongamos ahora que el primer proceso termina de escribir el fichero. Al acabar con el fichero debe incrementar el contador del semáforo. Al hacerlo, este contador se pone a 0. Como no es negativo, el semáforo se encarga de mirar el la cola de procesos pendientes y "desbloquear" al primer proceso de dicha cola. Con ello, el segundo proceso que quería acceder al fichero continua su ejecución y accede al fichero.

Cuando este proceso también termine con el fichero, incrementa el contador y el semáforo vuelve a ponerse a 1, a estar "verde".

Es posible hacer que el valor inicial del semáforo sea, por ejemplo, 3, con lo que pasarán los tres primeros procesos que lo intenten. Pueden a su vez quedar muchos procesos encolados simultáneamente, con lo que el contador quedará con un valor negativo grande. Cada vez que un proceso incremente el contador (libere el recurso común), el primer proceso encolado despertará. Los demás seguirán dormidos.

Como vemos, el proceso de los semáforos requiere colaboración de los procesos. Un proceso debe decrementar el contador antes de acceder al fichero e incrementarlo cuando termine. Si los procesos no siguen este "protocolo" (y pueden no hacerlo), el semáforo no sirve de nada.

Código de los Semáforos

Antes de nada, que quede claro que únicamente pretendo dar una idea sencilla de como funcionan los semáforos. No detallo aquí todas las opciones de las funciones a utilizar ni explico todas las posibilidades. Tampoco puedo garantizar que la sintaxis de las funciones y de los parámetros sea correcta al 100%, aunque sí suministro dos fuentes de ejemplo que compilan y funcionan. Hay, por tanto, que leer este texto con intención de hacer únicamente un uso sencillo de semáforos.

Para utilizar los semáforos en un programa, deben seguirse los siguientes pasos:

Como ejemplo de todo esto, están los programitas sem1.c y sem2.c que ya se han mencionado antes. Se compilan com make sem1 y make sem2. Para ejecutarlos, debe ejecutarse primero sem1 en una ventana de shell y luego sem2 en otra ventana de shell distinta.

sem1 tiene un bucle infinito para entrar en el semáforo. Escribe en pantalla cuando entra y cuando sale. Como el semáforo está en "rojo" por defecto, sem1 entra en él y no sale hasta que sem2 lo indica.

sem2 tiene un bucle de 1 a 10 en el que pone en verde el semáforo y espera un segundo. El resultado es que sem1 entra en el semáforo, queda "bloqueado" un segundo y sale del semáforo para volver a entrar en él y repetir el proceso 10 veces.

Puesto que las llamadas a la función semop() son bastante "engorrosas" por aquello de rellenar la estructura, suele ser útil hacer un para de funciones espera_semaforo() y eleva_semaforo() que realicen este código. Se les podría pasar el identificador del semáforo y el índice dentro del array de semáforos.

Hay una serie de comandos útiles de unix para manejo de recursos compartidos (semáfos, memoria compartida y colas).

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007:

Aviso Legal