Práctica - Universidad de Carabobo

Anuncio
Universidad de Carabobo
Facultad Experimental de Ciencias y Tecnología
Departamento de Computación
Sistemas Operativos
Prep. Carlos I. Buchart I.
Nombre:___________________________________
Sincronizacion y Comunicacion entre Procesos
Atomizacion de las operaciones: la arquitectura Intel 386, y posterior de la misma familia,
puede asegurar la atomicidad de las operaciones ejecutadas, una a una, simplemente añadiendo el
prefijo lock a la instruccion deseada.
lock add ax, bx
Inhabilitacion de Interrupciones: el problema de la seccion critica se genera cuando dos o
mas procesos desean acceder concurrentemente al mismo recurso. La solucion de I.I. evita que el
proceso abandone el CPU durante la S.C., logrando asi la exclusion mutua. El gran inconveniente que
presenta esta opcion es que desactivar y activar las interrupciones es muy costoso en lo que
respecta a tiempo de ejecución, por lo que no es una buena opcion para sistemas en tiempo real, por
ejemplo. El esquema general de uso seria el siguiente:
void Proceso(int id) {
// Desactivar las interrupciones
// S.C.
// Activar las interrupciones nuevamente
// S.n.C.
}
Test-And-Set: esta funcion verifica el estado de una variable cerrojo devolviendo verdadero
si el cerrojo estaba abierto (en 0), falso en otro caso. Ademas, al retornar, el cerrojo queda cerrado
(bien sea porque ya lo estaba o porque se cerro dentro de la funcion). Su uso es como se muestra a
continuacion:
int cerrojo=0;
void Proceso(int id) {
while(test_and_set(cerrojo));
// S.C.
cerrojo=0;
// S.n.C.
}
Swap: la instruccion swap, como su nombre indica, intercambia el valor de dos variables. Al
igual que con la instruccion anterior, esta otorga el acceso al primero que lo solicite una vez que el
recurso haya sido liberado. Del mismo modo, ambas instrucciones swap y t&s adolescen del
problema de “inversion de prioridad”.
int cerrojo=0;
void Proceso(int id) {
int clave=1;
do {
swap(clave,cerrojo);
} while(cerrojo);
// S.C.
swap(clave,cerrojo);
// S.n.C.
}
Semaforos: propuestos por Dijkstra en 1.965 como una solucion al problema de la seccion
critica. Consta de dos instrucciones signal y wait, y una variable mutex comun. Esta variable se suele
fijar al numero de recursos disponibles, la operacion wait decrementa su valor y verifica si no es
negativo (es decir, que al solicitarse habia alguno disponible); si no lo es, continua la ejecucion, en
caso contrario se puede utilizar espera activa o se puede bloquear el proceso e introducirlo en una
cola para evitar el consumo de CPU. El signal simplemente libera un recurso y en caso de utilizar
colas, libera el primer proceso de la misma.
int mutex=MAX_RECURSOS;
void signal(int *_mutex) {
(_mutex*)++;
if((*mutex)<=0)
// Desencolar un proceso
}
void wait(int *_mutex) {
(_mutex*)--;
if((*mutex)<0)
// Encolar un proceso
}
Paso de mensajes: este sistema de comunicacion tiene diversas implementaciones que solo
seran mencionadas: directa e indirecta; sin buffer, con buffer, bien sea limitado o “ilimitado”; con y
sin bloqueo. Se basa en un par de instrucciones send y receive, las cuales se encargan de enviar y
leer, respectivamente, un determinado mensaje, ya sea directamente a un proceso o bien sea a un
buzon o buffer.
Por ultimo, otro mecanismo de comunicacion sumamente utilizado en linux, es de las
tuberias, que no son mas que flujos unidireccionales de datos implementados por el shell.
Simplemente se toma la salida de un proceso y se usa como salida del siguiente. La implementacion
de esta tecnica es sumamente sencilla: se crea un archivo temporal en memoria y a este se
direcciona tanto el apuntador de stdout del primer proceso como el de stdin del segundo.
ls -la | grep 4096
Solucion al problema de los filosofos comensales en Linux, utilizando semaforos:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define NUM_FILOSOFOS
5
#define PENSANDO
#define COMIENDO
0
1
#define LIBRE
#define USADO
1
0
typedef struct datos_filosofos {
int filosofos[NUM_FILOSOFOS];
int pids[NUM_FILOSOFOS];
int semaforo_id,semaforo_id2;
int memoria_id;
} datos_filosofos;
struct datos_filosofos *p_filosofos;
// Reservar semáforos y memoria compartida
int crea_filosofos(void)
{
int i;
int sem_id,sem_id2,mem_id;
// Crea el área de memoria compartida
if((mem_id=shmget(IPC_PRIVATE,sizeof(datos_filosofos),0774 | IPC_CREAT))==-1)
return -1;
if(!(p_filosofos=(datos_filosofos *)shmat(mem_id,(char *)0,0)))
return -2;
// Crea el set de semáforos para los cubiertos
if((sem_id=semget(IPC_PRIVATE,NUM_FILOSOFOS,0774 | IPC_CREAT))==-1)
return -3;
// Crea el semáforo que evitará el interbloqueo
if((sem_id2=semget(IPC_PRIVATE,1,0774 | IPC_CREAT))==-1)
return -3;
// Inicializa el área de memoria compartida
for(i=0;i<NUM_FILOSOFOS;i++)
{
p_filosofos->filosofos[i]=PENSANDO;
p_filosofos->pids[i]=0;
semctl(sem_id,i,SETVAL,LIBRE);
}
semctl(sem_id2,0,SETVAL,NUM_FILOSOFOS-1);
p_filosofos->semaforo_id=sem_id;
p_filosofos->semaforo_id2=sem_id2;
p_filosofos->memoria_id=mem_id;
return sem_id;
}
// Liberar semáforos y memoria compartida
void elimina_filosofos(void)
{
int i;
int mem_id,sem_id;
mem_id=p_filosofos->memoria_id;
shmdt((char *)p_filosofos);
shmctl(mem_id,IPC_RMID,(struct shmid_ds *)NULL);
for(i=0;i<NUM_FILOSOFOS;i++)
semctl(sem_id,i,IPC_RMID);
}
// Wait
void P(int id,int i)
{
struct sembuf op[3]={i,-1,0};
semop(id,op,1);
}
// Signal
void V(int id,int i)
{
struct sembuf op[3]={i,1,0};
semop(id,op,1);
}
int main()
{
int res;
int i;
// Crea filósofos: reservar memoria, crear semáforos
res=crea_filosofos();
if(res<0)
{
printf("Error %d\n",-res);
return 0;
}
// Crea los filósofos (procesos hijos)
for(i=0;i<NUM_FILOSOFOS;i++)
if(!fork())
{
// Proceso hijo #i
p_filosofos->pids[i]=getpid();
while(1)
{
// Máximo NUM_FILOSOFOS-1 entran a tratar de comer para evitar el
interbloqueo
P(p_filosofos->semaforo_id2,0);
// Espera los dos cubiertos
P(p_filosofos->semaforo_id,i);
P(p_filosofos->semaforo_id,(i+1)%NUM_FILOSOFOS);
p_filosofos->filosofos[i]=COMIENDO;
sleep(1);
// Devuelve los dos cubiertos
V(p_filosofos->semaforo_id,i);
V(p_filosofos->semaforo_id,(i+1)%NUM_FILOSOFOS);
p_filosofos->filosofos[i]=PENSANDO;
// Deja que otro trate de comer
V(p_filosofos->semaforo_id2,0);
}
}
// Bucle de espera del proceso padre
while(res!=27)
{
// Muestra información
printf("Estado de los filósofos: \n");
for(i=0;i<NUM_FILOSOFOS;i++)
printf("%d[%d] ==> %d\n",i,p_filosofos->pids[i],p_filosofos->filosofo[i]);
res=getchar();
}
// Elimina los procesos hijos
for(i=0;i<NUM_FILOSOFOS;i++)
kill(p_filosofos->pids[i],9);
elimina_filosofos();
return 0;
}
Otros problemas a resolver: productor-consumidor, lectores-escritores.
Bibliografía
STALLINGS, William – Sistemas Operativos, segunda edicion. Pag. 175-209
TANENBAUM, Andrew – Sistemas Operativos, Diseño e Implementacion. Pag. 59-82
SILBERCHATZS, a – Sistemas Operativos, sexta edicion. Pag. 181-204
http://bernia.disca.upv.es/lxr/http/source/
http://es.tldp.org/Manuales-LuCAS/DENTRO-NUCLEO-LINUX/dentro-nucleo-linux-html/dentro-nucleolinux-2.html
http://www.icselectionguide.com/real_time_dispatch.html
http://www.codecomments.com/archive258-2004-12-343766.html
http://www.linux-tutorial.info/modules.php?name=Tutorial&pageid=288
CB/cb
Descargar