martes, 13 de enero de 2009

Semáforos para Linux

A veces se tienen varios procesos que deben de usar un recurso compartido, pero si los dos usaran el recurso al mismo tiempo provocarían un problema.
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.

Necesito usar semáforos pero que sean del sistema operativo Linux, para ello se usan semáforos desde c.
Pondré un ejemplo de dos procesos que se ejecutan usando los semáforos,


Archivo 1
ej_sem1.c

#include 
#include
#include
#include
#include

// Esta union hay que definirla o no según el valor de los defines aquí indicados.

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
// La union ya esta definida en sys/sem.h
#else
// Tenemos que definir la union
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
#endif

int main(void)
{
key_t Clave;
int Id_Semaforo;
struct sembuf Operacion;
union semun arg;
int i=0;

// Igual que en cualquier recurso compartido (memoria compartida, semaforos
// o colas) se obtien una clave a partir de un fichero existente cualquiera
// y de un entero cualquiera. Todos los procesos que quieran compartir este
// semaforo, deben usar el mismo fichero y el mismo entero.

Clave = ftok ("/bin/ls", 33);
if (Clave == (key_t)-1)
{
printf("No puedo conseguir clave de semaforo\n");
exit(0);
}

// Se obtiene un array de semaforos (10 en este caso, aunque solo se usara uno.
// El IPC_CREAT indica que lo cree si no lo está
// el 0600 con permisos de lectura y escritura para el usuario que lance
// los procesos. Es importante el 0 delante para que se interprete en
// octal.

Id_Semaforo = semget (Clave, 10, 0600 | IPC_CREAT);
if (Id_Semaforo == -1)
{
printf("No puedo crear semaforo\n");
exit (0);
}

// Se inicializa el semáforo con un valor conocido. Si lo ponemos a 0,
// el semáforo estará "rojo". Si lo ponemos a 1, estará "verde".
// El 0 de la función semctl es el índice del semáforo que queremos
// inicializar dentro del array de 10 que hemos pedido.

arg.val = 0;
semctl (Id_Semaforo, 0, SETVAL, &arg);


// Para "pasar" por el semáforo si está "rojo", debemos rellenar esta estructura.
// sem_num es el indice del semáforo en el array por el que queremos "pasar"
// sem_op es -1 para hacer que el proceso espere al semáforo.
// sem_flg son flags de operación. De momento nos vale un 0.

Operacion.sem_num = 0;
Operacion.sem_op = -1;
Operacion.sem_flg = 0;

// Bucle infinito indicando cuando entramos al semáforo y cuándo salimos
// de él.
// i hace de contador del número de veces que hemos salido del semáforo.
//
while (1)
{
printf("%i Esperando semaforo\n",i );

// Se hace la espera en el semáforo. Se le pasa un array de operaciones
// y el número de elementos en dicho array. En nuestro caso solo 1.

semop (Id_Semaforo, &Operacion, 1);
printf("%i Salgo de Semaforo\n ",i);
i++;
}
}



Y adjunto el segundo archivo con el otro semáforo,

Archivo 2
ej_sem2.c


#include
#include
#include
#include
#include
#include

// Esta union hay que definirla o no según el valor de los defines aqui indicados.

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
// La union ya está definida en sys/sem.h
#else
// Tenemos que definir la union

union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
#endif

int main(void)
{
key_t Clave;
int Id_Semaforo;
struct sembuf Operacion;
union semun arg;
int i;

// Igual que en cualquier recurso compartido (memoria compartida, semaforos
// o colas) se obtien una clave a partir de un fichero existente cualquiera
// y de un entero cualquiera. Todos los procesos que quieran compartir este
// semaforo, deben usar el mismo fichero y el mismo entero.

Clave = ftok ("/bin/ls", 33);
if (Clave == (key_t)-1)
{
printf("No puedo conseguir clave de semaforo\n");
exit(0);
}

// Se obtiene un array de semaforos (10 en este caso, aunque solo se usara uno.
// El IPC_CREAT indica que lo cree si no lo esta
// el 0600 con permisos de lectura y escritura para el usuario que lance
// los procesos. Es importante el 0 delante para que se interprete en
// octal.

Id_Semaforo = semget (Clave, 10, 0600 | IPC_CREAT);
if (Id_Semaforo == -1)
{
printf("No puedo crear semaforo\n");
exit (0);
}

// Se levanta el semáforo. Para ello se prepara una estructura en la que
// sem_num indica el indice del semaforo que queremos levantar en el array
// de semaforos obtenido.
// El 1 indica que se levanta el semaforo
// El sem_flg son banderas para operaciones raras. Con un 0 vale.
//
Operacion.sem_num = 0;
Operacion.sem_op = 1;
Operacion.sem_flg = 0;

// Vamos a levantar el semáforo 10 veces esperando 1 segundo cada vez.

for (i = 0; i<10;>

Para correr los archivos .c se compilan en consola con:
# gcc  ej_sem1.c -o ej_sem1

Y para correrlo:
# ./ej_sem1


Lo mismo con el segundo archivo, se corre cada uno en una consola diferente y veremos como funcionan los semáforos del sistema operativo linux/unix.

Para mayor referencia visiten este sitio:
http://www.chuidiang.com/clinux/ipcs/semaforo.php

1 comentarios:

Anónimo dijo...

bueno gracias por la buena intencion pero estaria chido que pusieras el segundo codigo completito pero detodas formas logre disolver algunas dudas gracias atte RamBai..

 
;