Semáforos
Los semáforos son un mecanismo de sincronización utilizado para controlar el acceso a un recurso compartido por varios procesos o hilos. Un semáforo es una variable entera que se puede incrementar (releasing) o decrementar (waiting) de manera atómica.
Los semáforos se utilizan para implementar bloqueos o mutexes, que permiten que solo un proceso o hilo tenga acceso a un recurso determinado en un momento dado. Esto es útil para evitar conflictos de acceso y garantizar la consistencia de los datos.
Existen dos variedades de semáforos: los semáforos tradicionales de System V y los semáforos POSIX, los más recientes. En este post, veremos los semáforos POSIX.
Explicación sencilla
Los semáforos son una forma de controlar el acceso a un juguete o un juego que varios niños quieren usar al mismo tiempo. Cada vez que un niño quiere usar el juguete o juego, debe pedir permiso a un semáforo. Si el semáforo está en verde, significa que puede usar el juguete o juego. Si está en rojo, significa que otro niño está usándolo y debe esperar a que termine.
De esta manera, los semáforos ayudan a evitar peleas y conflictos entre los niños al jugar con los juguetes y aseguran que todos tengan una oportunidad justa de disfrutarlos.
sem_open
sem_open
es la llamada para comenzar a utilizar un semáforo. sem_open
abre un semáforo existente o crea un semáforo nuevo y lo abre para realizar operaciones adicionales.
name
El argumento "name" de la función sem_open
es el nombre del semáforo que se está abriendo o creando. El nombre del semáforo es una cadena de caracteres que se utiliza para identificar al semáforo y permitir el acceso a él por diferentes procesos o hilos.
El nombre del semáforo se utiliza para crear un archivo en el sistema de archivos que representa al semáforo. Este archivo se encuentra en el directorio "/dev/shm" y tiene un prefijo "sem." seguido del nombre del semáforo. Por ejemplo, si se crea un semáforo con el nombre "/mysem", se creará un archivo con el nombre "/dev/shm/sem.mysem".
Es importante tener en cuenta que el nombre del semáforo es compartido entre todos los procesos o hilos que deseen utilizar el semáforo. Por lo tanto, es necesario utilizar nombres únicos para evitar conflictos con otros semáforos. Además, es importante recordar que el nombre del semáforo es una cadena de caracteres y no un número entero, por lo que no se puede utilizar como un identificador único para el semáforo.
Una manera visual de declarar el nombre de los semaforos es mediante macros:
oflag
El segundo parámetro de la función sem_open
es una cadena de banderas que indica cómo se deben abrir o crear el semáforo.
El parámetro "oflag" es una combinación de una o más banderas que se pueden utilizar para controlar el comportamiento de la función. Las banderas más comunes que se pueden utilizar en el parámetro "oflag" son:
O_CREAT
: Indica que el semáforo debe ser creado si no existe. Si se especifica esta bandera, se debe utilizar la segunda forma de la funciónsem_open
, que incluye dos parámetros adicionales: "mode" y "value".O_EXCL
: Indica que la llamada asem_open
debe fallar y establecer el valor deerrno
con el error "EEXIST" si el semáforo ya existe.O_RDONLY
: Indica que el semáforo se abrirá en modo de lectura solamente.O_WRONLY
: Indica que el semáforo se abrirá en modo de escritura solamente.O_RDWR
: Indica que el semáforo se abrirá en modo de lectura y escritura.
En el caso de que no queda clara la diferencia entre O_CREAT
y O_RDWR
, la bandera O_RDWR
indica el modo en que se abre el semáforo (lectura y escritura) mientras que la bandera O_CREAT
indica que se debe crear el semáforo si no existe. Ambas banderas se pueden utilizar juntas para abrir o crear un semáforo en modo de lectura y escritura.
O_RDWR
abre un semáforo existente, y solo funciona si el samaforo ya ha sido creado. En cambioO_CREAT
en el caso de que el semáforo no exista lo crea
Es importante tener en cuenta que la bandera O_RDWR
no tiene ningún efecto si se utiliza sin la bandera O_CREAT
, ya que el semáforo ya debe existir para poder abrirlo en modo de lectura y escritura. Por otro lado, la bandera O_CREAT
sí puede utilizarse sin la bandera O_RDWR
, en cuyo caso se creará el semáforo con permisos de lectura y escritura por defecto
Si un semáforo se abre con permisos de escritura, se podran aplicar las funciones sem_wait y sem_post sobre el. En cambio si solo tiene permisos de lectura no se podra utilizar estas funciones y solo se podra ver su valor mediante sem_getvalue.
En el caso de que tenga ambos permisos se podrán utilizar todas las funciones, como en el siguiente ejemplo:
mode
El tercer parámetro de la función sem_open
es el parámetro mode
, que especifica los permisos del semáforo. Este parámetro se utiliza solamente cuando se utiliza la bandera O_CREAT
para crear un semáforo nuevo.
El parámetro "mode" es un valor entero que especifica los permisos de lectura, escritura y ejecución para el semáforo. El valor del parámetro "mode" se establece utilizando los octales rwx
para representar los permisos de lectura, escritura y ejecución, respectivamente. Los permisos se pueden establecer para el usuario dueño del semáforo, el grupo del usuario dueño y para el resto de usuarios.
Por ejemplo, el valor 0666
indica que el semáforo se debe crear con permisos de lectura y escritura para todos los usuarios. El valor 0600
indica que el semáforo se debe crear con permisos de lectura y escritura solamente para el usuario dueño.
value
El cuarto parámetro de la función sem_open
es el parámetro "value", que especifica el valor inicial del semáforo. Este parámetro se utiliza solamente cuando se utiliza la bandera O_CREAT
para crear un semáforo nuevo.
El parámetro "value" es un valor entero que especifica el valor inicial del semáforo. Este valor se utiliza para inicializar el semáforo cuando se crea por primera vez. El valor del parámetro "value" puede ser cualquier entero entero mayor o igual a 0.
Por ejemplo, el valor "1" indica que el semáforo se debe crear con un valor inicial de "1", lo que significa que se puede utilizar de inmediato para sincronizar un proceso o hilo. El valor "0" indica que el semáforo se debe crear con un valor inicial de "0", lo que significa que se debe bloquear un proceso o hilo hasta que el valor del semáforo sea incrementado por otro proceso o hilo.
Ejemplo
En el ejemplo anterior, se utiliza la bandera O_CREAT
para indicar que el semáforo debe ser creado si no existe. También se especifica el parámetro "mode" con el valor "0666", que indica que el semáforo se debe crear con permisos de lectura y escritura para todos los usuarios. Si el semáforo ya existe, la llamada a sem_open
devolverá un puntero al semáforo y no creará uno nuevo.
Como podeis ver, se pueden utilizar mas de una flag y en este caso tambien utilizamos la flag
O_EXCL
, para que en caso de que el semáforo ya exista el función sem_open
nos devuelva un error.
sem_wait
La función sem_wait
en C es una función de la biblioteca de semáforos de POSIX que se utiliza para bloquear a un proceso o hilo hasta que el valor de un semáforo sea mayor o igual que uno. La función tiene la siguiente forma:
La función sem_wait
toma como parámetro un apuntador a la estructura sem_t
que representa el semáforo sobre el que se desea esperar. La función devuelve 0 en caso de éxito y -1 en caso de error, estableciendo el valor de la variable global errno
con el código de error correspondiente.
La función sem_wait
se utiliza para bloquear a un proceso o hilo hasta que el valor del semáforo sea mayor o igual que uno. Si el valor del semáforo es mayor o igual que uno antes de llamar a sem_wait
, la función decrementará el valor del semáforo en una unidad y permitirá que el proceso o hilo continúe su ejecución. Si el valor del semáforo es menor que uno antes de llamar a sem_wait
, la función bloqueará al proceso o hilo y lo pondrá en espera hasta que el valor del semáforo sea incrementado por otro proceso o hilo mediante una llamada a sem_post
.
Ejemplo de código que utiliza la función sem_wait
para bloquear a un proceso o hilo hasta que el valor del semáforo sea incrementado por otro proceso o hilo:
En el ejemplo anterior, se abre o crea un semáforo con un valor inicial de 0 utilizando la función sem_open
. Luego, se llama a la función sem_wait
para bloquear al proceso o hilo hasta que el valor del semáforo sea incrementado por otro proceso o hilo mediante una llamada a sem_post
.
Si el valor del semáforo es 0 antes de llamar a sem_wait
, la función bloqueará al proceso o hilo y lo pondrá en espera hasta que otro proceso o hilo incremente el valor del semáforo mediante una llamada a sem_post
. Una vez que el valor del semáforo es mayor o igual que uno, la función sem_wait
decrementará el valor del semáforo en una unidad y permitirá que el proceso o hilo que había sido bloqueado continúe su ejecución.
sem_post
La función sem_post
en C es una función de la biblioteca de semáforos de POSIX que se utiliza para incrementar el valor de un semáforo en una unidad. La función tiene la siguiente firma:
La función sem_post
toma como parámetro un apuntador a la estructura sem_t
que representa el semáforo al que se le desea incrementar el valor. La función devuelve 0 en caso de éxito y -1 en caso de error, estableciendo el valor de la variable global errno
con el código de error correspondiente.
La función sem_post
se utiliza para incrementar el valor del semáforo en una unidad. Si el valor del semáforo es 0 antes de llamar a sem_post
, la función desbloqueará a un proceso o hilo que esté esperando en la llamada a sem_wait
sobre el semáforo. Si el valor del semáforo es mayor que 0 antes de llamar a sem_post
, la función simplemente incrementará el valor del semáforo en una unidad.
Ejemplo de código que utiliza la función sem_post
para incrementar el valor de un semáforo y desbloquear a un proceso o hilo que esté esperando en una llamada a sem_wait
:
En el ejemplo anterior, se abre o crea un semáforo con un valor inicial de 0 utilizando la función sem_open
. Luego, se llama a la función sem_post
para incrementar el valor del semáforo en una unidad. Si hay un proceso o hilo que esté esperando en una llamada a sem_wait
.
Ejemplo
En resumen, el código crea o abre un semáforo con un valor inicial de 1 mediante la función sem_open
. Luego, crea un proceso hijo mediante la función fork
. En el proceso hijo, se llama a la función sem_wait
para bloquear al proceso hijo hasta que el valor del semáforo sea mayor o igual que uno. Mientras tanto, en el proceso padre, se obtiene el semáforo sin tener que esperar debido a que el valor del semáforo es inicialmente mayor o igual que uno.
Cuando el proceso hijo finalmente obtiene el semáforo, ambos procesos acceden al recurso compartido y luego liberan el semáforo mediante una llamada a sem_post
. Gracias al uso del semáforo, se garantiza que el acceso al recurso compartido se realiza de manera sincronizada y que sólo un proceso puede acceder al recurso a la vez.
Last updated