Informática


Programación en Unix


'Programación en Unix'

Instituto Profesional

LA ARAUCANA

IPLA

Ingeniería (E) en Computación e Informática

TAREA

“SEMAFOROS Y EL PROBLEMA DE LOS FUMADORES DE CIGARRILLOS”

Santiago

JULIO 2000

PLANTEAMIENTO DEL PROBLEMA

Problema de los fumadores de cigarrillos (S.S.Patil)

Tres fumadores están representado por los procesos F1, F2, y F3. Tres vendedores están representados por los procesos V1, V2, y V3. Para fumar, cada fumador necesita, tabaco, papel para tabaco y un fosforo; cuando dispone de estos recursos el fumador fuma un cigarrillo hasta terminarlo y entonces que elegible para fumar de nuevo. F1 tiene tabaco, F2 tiene papel y F3 tiene fosforos. V1 vende tabaco y papel, V2 vende papel para tabaco y fosforos y V3 vende fosforos y tabaco. V1, V2 y V3 trabajan en exclusión mutua, solo uno d elos procesos puede trabajar a la vez y el siguiente vendedor no puede trbajar hasta que los recursos sumistrados por el vendedor anterior hallan sido consumidos por un fumador.

F1 tabaco V1 tabaco - papel

F2 Papel V2 papel - fosforos

F3 Fosforos V3 fosforo - tabaco

Solución Algoritmica

Procedimiento Principal

Numero_fumador es igual a 1

Vendedor_numero es igual a 2

Par Begin

Ejecute procedimiento Fumador uno

Ejecute procedimiento Fumador dos

Ejecute procedimiento Fumador tres

ParEnd

Fin procedimiento

Procedimiento Fumador uno

Mientras sea verdadero

Mientras numero_fumador es igual a 2 ó numero_fumador es igual a 3 y vendedor_numero es igual a 1 ó vendedor_numero es igual a 3

Fumador uno compra a vendedor dos

Fumador uno fuma

Numero_fumador queda en 2

Vendedor_numero queda en 3

Fumador uno espera fumar otra vez

Fin Mientras

Fin Mientras

Fin procedimiento

Procedimiento Fumador dos

Mientras sea verdadero

Mientras numero_fumador es igual a 1 ó numero_fumador es igual a 3 y vendedor_numero es igual a 1 ó vendedor_numero es igual a 2

Fumador dos compra a vendedor tres

Fumador dos fuma

Numero_fumador queda en 3

Vendedor_numero queda en 1

Fumador dos espera fumar otra vez

Fin Mientras

Fin Mientras

Fin procedimiento

Procedimiento Fumador tres

Mientras sea verdadero

Mientras numero_fumador es igual a 1 ó numero_fumador es igual a 2 y vendedor_numero es igual a 2 ó vendedor_numero es igual a 3

Fumador tres compra a vendedor uno

Fumador tres fuma

Numero_fumador queda en 1

Vendedor_numero queda en 2

Fumador tres espera fumar otra vez

Fin Mientras

Fin Mientras

Fin procedimiento

SEMAFOROS

En 1965 E.W. Dijkstra sugirió el uso de una variable entera para contar el número de desbloqueos guardados para uso futuro. En esta proposición, se introdujo un nuevo tipo de variable, llamada semáforo. Un semáforo podía tener el valor 0, lo que indicaba que no se habian guardado desbloqueos o algún valor positivo si quedaban pendientes uno o más desbloqueos.

Dijkstra propuso contar con dos operaciones, DOWN y UP (generalizaciones de SLEEP y WAKEUP, respectivamente). La operación DOWN con un semáforo verifica si el valor es mayor que 0. Si es así, disminuye el valor (es decir, utiliza un desbloqueo almacenado) y simplemente prosigue. Si el valor es 0, el proceso se bloquea. La verificación del valor, su alteración y posiblemente su bloqueo se realizan en una sola acción atómica indivisible. Se garantiza que una vez que se haya dado inicio a una operación del semáforo, ningún otro proceso puede accesarlo hasta que se complete la operación.

La operación UP incrementa el valor del semáforo direccionado. Si uno o más procesos estaban bloqueados en ese semáforo, incapaces de completar una operación DOWN anterior, el sistema elige uno de ellos al azar y le permite completar su operación (DOWN). Por lo tanto, después de una operación UP con un semáforo con procesos bloqueados en él, el semáforo seguirá siendo 0, pero habrá un proceso bloqueado menos en él. La operación de incrementar el semáforo y desbloquear un proceso también es indivisible. Ningún proceso se bloquea realizando una operación UP, así como tampoco ningún proceso se bloquea realizando una operación WAKEUP en el modelo anterior.

Además, en el manuscrito original de Dijkstra, él utilizó los nombres de P y V en lugar de Down y UP, respectivamente, pero ya que éstos no tienen significado mnemotécnico para quienes no hablan alemán, utilizaremos los términos DOWN y UP en su lugar.

Los semáforos resuelven el problema del desbloqueo perdido. Es esencial que se implanten en forma indivisible. La forma normal consiste en implementar UP y DOWN como llamadas al sistema, donde el sistema operativo desactiva brevemente todas las interrupciones mientras prueba el semáforo, lo actualiza y bloquea el proceso, si es que se necesita. Como todas estas acciones emplean sólo una cuantas instrucciones, no se causa daño al desactivar las interrupciones. Si se utilizan múltiples CPU, cada semáforo debe protegerse con una variable de cierre, utilizando la instrucción TSL para asegurar que sólo una CPU a la vez examine el semáforo.

SEMAFOROS EN UNIX

  • Semáforos multi-valuados, no binarios

  • Se puede crear un arreglo de semáforos con una simple llamada

  • Posibilidad de especificar una sola operación en un solo semáforo

  • Posibilidad de especificar un conjunto de operaciones en un arreglo de semáforos

  • En UNIX, cuando un proceso aborta (exit() ) libera todos los candados, ( locks ), que retenía en sus semáforos

  • Los semáforos tienen dueños, modos de acceso y timestamps

  • Librerías:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

PARTICULARIDADES DE LOS SEMAFOROS EN UNIX

  • Petición de m recursos del conjunto { R1, R2......... Rm }

Cada uno protegido por un semáforo (Si)

Acceso de m recursos : R1, R2......... Rm

P(S1) P(S2).......... P(Sm)

Atomicidad no garantizada:

Posibilidad de bloqueo de un proceso y de que

que éste bloquee a otro

  • UNIX: posibilidad de realizar conjunto de operaciones sobre un conjunto de semáforos. Si una operación no es posible, ninguna se realiza.

  • Adquisición de m recursos del mismo tipo:

m operaciones P sucesivas del mismo semáforo

mismas consecuencias

  • Despertar procesos en espera del valor de un semáforo:

UNIX despierta a todos los procesos qu% se encontraban en espera de un evento, dejando al administrador, que decida quien entra.

ESTRUCTURA DE DATOS SEMAFOROS

EJEMPLO RELACION ESTRUCTURA

semget(key, nsems, flag)

  • Crea un arreglo de semáforos de tamaños nsems

  • Obtiene un manejador de un conjunto de semáforos

id = semget(key, nsems, flag)

key_type key

llave de identificación del semáforo

int nsems

número de semáforos requerido en el segmento

int flag

si tiene el valor de:

IPC_CREAT crea un semáforo con permisos especificados en perms:

(IPC_CREAT | perms)

0 obtiene un manejador del semáforo existente

int id

manejador del semáforo

semop(id,ops,nops

  • Permite realizar atómicamente nops operaciones, definidas en **ops, sobre el arreglo de semáforos ubicado en semid

  • Primitiva bloqueante

semop(id,ops,nops)

int id

manejador de semáforos, obtenido en semget()

struct sembuf **ops

definición de la operación a partir de la estructura:

struct sembuf{

short sem_num; /* número semáforo */

short sem_op; /* operación semáforo */

short sem_flg; /* parámetro operación */

}

int nops

número de operaciones

semop(id, ops, nops)

+ Operaciones atómicas sobre semáforos

Naturaleza operaciones semop()

Operación elemental que engloba un número de semáforo y una operación. Esta puede tener 3 tipos de valor

1) Valor estrictamente Negativo

+ Especifica una operación tipo P(S)

+ Tiene por objeto disminuir el valor del semáforo(S)

+ Si la operación no es posible el proceso se duerme

esperando que el valor del semáforo aumente.

2) Valor estrictamente Positivo

+ Especifica una operación tipo V(S)

+ Tiene por objeto aumentar el valor del semáforo(S)

+ Tiene el efecto de despertar todos los procesos en espera

de que el valor del semáforo (S) aumente

3) Valor 0 (nulo)

+ Permite probar si el valor del semáforo es 0

+ Si no es el caso el proceso es bloqueado

Definición operaciones en semop()

if (sem_op < 0)

if (semval >= abs(sem_op ) => semval = semval - abs(sem_op)

else

+ incrementar valor semcnt de la estructura sem

+ proceso bloqueado hasta que:

1) semval >= abs(sem_op )

2) arreglo semáforos desaparece

3) proceso recibe señal indica que semcnt es decrementada

if (sem_op > 0 ) => semval = semval + sem_op

(liberaración recursos que controlaba el semáforo)

if (sem_op = 0 )

if (semval = 0) => regreso inmediato

else

+ incrementar en 1 el campo semzcnt de la estructura sem

+ proceso suspendido hasta que:

1) semval = 0, (semzcnt es decrementado)

2) arreglo semáforos desaparece

3) proceso recibe señal

Parámetros operaciones en semop()

Bandera IPC_NOWAIT

Operaciones no bloqueantes

Si durante la ejecución de semop( ) una operación no puede

ser ejecutada ninguna lo es pero el proceso no se bloquea.

Si ( sem_op es negativo)

si (semval < abs(sem_op) ) entonces

regreso inmediato con estatus de error

errno = 11, (EAGAIN)

Si ( sem_op es cero )

si (semval es diferente de cero) entonces

regreso inmediato con estatus de error

errno = 11 (EAGAIN)

No aplica para sem_op positivo

Bandera SEM_UNDO

Prevención de bloqueo accidental de recursos

Cuando esta activada y se asignan recursos (sem_op > 0) kernel maneja un valor de ajuste para recordar cuantos “recursos” se le han asignado

Si el proceso termina, voluntaria o involuntariamente el kernel verifica si el proceso tiene ajustes pendientes y en caso positivo aplica el ajuste correspondiente.

Relación con operaciones:

sem_op > 0 => ajuste = ajuste - sem_op

sem_op < 0 => ajuste = ajuste + abs(sem_op)

Creación semáforos

/* Construcción de un arreglo de n semáforos con llave k */

int construye_sem(k, n)

key_t k;

int n;

{

int semid, i;

/* intenta accesar un conjunto de semáforos con la llave k */

/* Si existe lo destruye */

if ( (semid = semget(k,n,0)) != -1)

semctl(semid, 0, IPC_RMID);

/* Valores semáforos inicializados en cero, lo que implica */

/* que todos los recursos están bajo candado */

/* Hay que quitarles ese candado a cada uno */

if ((semid = semget(k, n, IPC_CREAT | 0600)) != -1) {

for (i=0; i<=n; i++)

V(semid, i);

}

return semid;

}

Lock de un sémaforo P(S)

/* Poniendo un candado al semáforo n*/

void P(sem, n)

int sem;

int n;

{

struct sembuf sop;

/* construcción arreglo operaciones de un elemento */

sop.sem_num = n;

sop.sem_op = -1; /* bloquea solo una unidad */

sop.sem_flg = 0;

/* bloquea hasta que el recurso sea liberado */

semop(sem, &sop, 1);

}

Unlock de un semáforo V(S)

/* Quitando un candado al semáforo n del conjunto sem */

void V(sem, n)

int sem;

int n;

{

struct sembuf sop;

/* construcción arreglo operaciones de un elemento */

sop.sem_num = n;

sop.sem_op = 1; /* +1 -> desbloquea */

sop.sem_flg = 0;

semop(sem, &sop, 1);

}

semctl(id, num, cmd, arg)

  • Permite realizar diferentes comandos, cmd , sobre un arreglo de semáforos apuntado por id, o sobre algun(os) semáforos del mismo arreglo.

  • Inicialización, borrado, etc.

semctl(id, num, cmd, arg)

int id

manejador del semáforo

int num

especificación de los semáforos a procesar dentro del arreglo

int cmd

comando u operación a realizar

union semnum arg

argumento de la operación definida dentro de la unión semnum

El argumento de operación de semctl()

union semnum arg

arg es una unión definida de la siguiente forma:

union semnum {

int val; /* usado en SETVAL */

struct semid_ds *buf; /* usado en IPC_STAT y IPC_SET*/

ushort *array; /* usado en GETALL y SETALL*/

}

la estructura de semid es:

struct semid_ds {

struct ipc_perm sem_perm; /* estructura permiso */

int *pad; /* usado por sistema */

ushort sem_nsems; /* número semáforos */

time_t sem_otime; /* tiempo último semop */

time_t sem_ctime; /* tiempo último cambio */

}

siendo la estructura del permiso:

struct ipc_perm {

ushort uid; /* id del usuario actual*/

ushort gid; /* id del grupo actual */

ushort cuid; /* id del usuario creador */

ushort cgid; /* id del grupo creador */

ushort mode; /* modo de acceso */

short pad1; /* usado por el sistema*/

long2 pad2; /* usado por el sistema */

}

Posibles operaciones en semctl()

Función para borrar semáforos

/* Borra semaforo especificado por sem */

int borra_sem (sem)

int sem;

{

int status;

status= semctl (sem, 0, IPC_RMID);

if (status < 0) {

fprintf (stderr, “\n Error %d al borrar el semáforo \n”, errno);

return (-1);

}

else

return (status);

}

Función asignar un valor x al e-nésimo semáforo

/* Asigna el valor x al semáforo n de sem */

int asig_val.sem(sem, n, x)

int sem, x, n;

{

union {

int val;

struct semid_ds *buf;

ushort *array;

} semctl_arg;

semctl_arg.val = x

if (semctl(sem, n, SETVAL, semctl_arg) <0) {

fprintf (stderr, “Error %d en la asignación de valores \n”, errno);

return (-1);

}

else

return (0);

}

Verificar valor e-nésimo semáforo

/* Regresa el valor del semáforo n de sem */

int valsem_n(sem, n)

int sem, n;

{ int semval;

union {

int val;

struct semid_ds *buf;

ushort *array;

} semctl_arg;

semval = semctl (sem, n, GETVAL, semctl_arg);

if (semval < 0) {

fprintf (stderr, “Error % d en lectura valor semáforo \n”, errno);

return (-1);

}

else

return (semval);

}

Función regresa valor semáforo sem

/* Regresa el valor del semáforo sem */

int imp_semval (sem)

int sem;

{ int semval;

union {

int val;

struct semid_ds * buf;

vshort * array;

} semctl_arg;

semval = semctl (sem, 0, GETVAL, semctl_arg)

if (semval < 0) {

fprintf (stderr,“Error %d en lectura semáforo: % d \n”,

errno, sem);

return (-1);

}

else

return (semval);

}

Ejemplo aplicación funciones

#include <stdio.h>

#include <errno.h>

#include <sys/ types..h>

#include <sys/ ipc.h>

#include <sys/shm.h>

#include <sys/ sem.h>

#include “semop.h”

#define KEY_SEM IPC_PRIVATE

#define KEY_SEM2 (key_t) 275463

#define KEY_SEM3 37416

main ()

{

int sema3, mutex, sema, i, n;

if ((sema3 = semget(KEY_SEM3, 5, IPC_CREAT|0666 )) <O) {

fprintf(stderr, “Error %d en creación directa semáforo \n”,errno);

exit (1);

}

if ((sema = construye_sem(KEY_SEM, 3)) >= 0)

printf (“Creación exitosa \n” );

/* se crea un arreglo de semáforos con un solo elemento */

if ((mutex = construye_sem(KEY_SEM2, 1)) < 0) {

printf(“Error en la creación \n”);

exit(3) ;

}

/* impresión de los valores de los semáforos: */

printf (“Impresión valores sema3: \n”) ;

for (i=0; i<5; i++)

printf (“ Valor sem[%d]:%d\n” , i, valsem_n(sema3, i)) ;

printf (“Valor semáforo mutex:%d”, imp_semval(mutex) ) ;

/* asignado los valores de 1, 2 y 3 al semáforo 0, 1 y 2, */

/* respectivamente, de sema3 */

for (i=1: i<=3; i ++)

asig_val_sem(sema, i-1, i) ;

/* asignando el valor se 5 al semáforo mutex */

asig_val_sem (mutex, 0, 5) ;

/* impresión de los valores de los semáforos: */

printf (“ Impresión semáforos después asignación:\n”) ;

printf (“ Impresión valores sema3: \n” ) ;

for (i=0; i<3; i++)

printf(“Valor sem %d de sem3: %d \n”, i, valsem_n(sema3, i)

printf (“Valor semáforo mutex:%d”, imp_semval (mutex) ) ;

/* impresión de los semáforos existentes en ese momento */

printf (“\n Semáforos existentes:\n” ) ;

system ( “ipcs -s”) ;

/*borrar los semáforos*/

borra_sem (sema3) ;

borra_sem (mutex) ;

/* impresión de los semáforos */

printf (“\n Semáforos existentes:\n”);

system ( “ipcs -s” ) ;

}

Ejemplo : Implementación Productor Consumidor

* Dos procesos

Consumidor

Productor

* Tres semáforos

vacío

lleno

mutex

* Sección Crítica

memoria compartida

cada proceso despliega:

El contenido del almacen y el número de

casillas libres y llenas

* Fuera de sección crítica

produce_item()

Despliega: “Produciendo un item”

consume_item()

Despliega: “Consumiendo item”

Código del ejemplo 1

#include <stdio.h>

#include <sys/types>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>

#include <semop.h>

#define KEY_SHMEM (key_t) 447885

#define KEY_MUTEX (key_t) 478854

#define KEY_LLENO (key_t) 788544

#define KEY_VACIO (key_t) 885447

#define N 10

#define LLENO 5

#define SEGSIZE (size of (struct info))

int mutex, full, empty; /*variables semaforos */

int tmp_prod, tmp_cons; /* variables tiempo asignacion*/

int i;

int id;

struct info {

int index;

int almacen[N];

};

struct shmid_ds shmbuf;

struct info *ptg;

main()

{

int k;

/* verificando valores de entrada */

if (argc != 3 ) {

printf(“Error: %s tmp:cons tmp:prod \n”,argv[0]);

exit(1);

}

/* asignando tiempos de atencion */

tmp_cons=atoi(argv[1]);

tmp_prod=atoi(argv[2]);

/* creación de la memoria compartida */

id = shmget(KEY_SHMEM, SEGSIZE, IPC_CREAT | 0666);

if (id <0) {

fprintf(stderr,“ Error en el shmget \n“);

exit(1);

}

ptg = (struct info*) shmat(id, 0, 0);

/* creando los semáforos */

mutex = crea_semas(KEY_MUTEX, 1);

lleno = crea_semas(KEY_LLENO, 1);

vacío = crea_semas(KEY_VACIO, 1);

/* limpiando la pantalla, inicializando e imprimiendo valores

semáforos */

system(“clear”);

printf(“ Valores Iniciales Semáforos: \n”);

asig_val_sem(mutex, 0, 1);

asig_val_sem(vacío, 0, N-LLENO);

asig_val_sem(lleno, LLENO);

imprime_valores(1);

/* incialización del almacen */

for (k=0; k<LLENO; k++)

if (k <LLENO)

ptg->almacen[k] = 1;

else

ptg->almacen[k] = 0;

ptg->index = LLENO;

/*inicialización simulación y lanzamiento de los procesos */

printf(“PROCESO CONSUMIDOR”);

printf(“\t\t\t\t\t PROCESO PRODUCTOR \n”);

if(fork() == 0){

productor();

}

else {

consumidor();

}

/* desatando memoria y borrando memoria y semáforos */

shmdt(0);

shmctl(id, IPC_RMID, shmbuf);

semctll(mutex, 0, IPC_RMID);

semctll(lleno, 0, IPC_RMID);

semctll(vacio, 0, IPC_RMID);

}

productor()

{

printf(“ \nEmpieza ejecución productor %d \n”, getpid());

while (1) {

produce_item();

P(vacío, 0);

P(mutex, 0);

enter_item(item);

V(mutex, 0);

V(lleno, 0);

sleep(tmp_prod);

}

}

consumidor()

{

printf(“ \nEmpieza ejecución consumidor %d \n”,getpid());

while (1) {

P(lleno, 0);

P(mutex, 0);

remove_item(item);

V(mutex, 0);

V(vacío, 0);

consume_item();

sleep(tmp_cons);

}

}

/* produciendo un elemento */

produce_item()

{

printf(“Proc %d produciendo un item \n”, getpid());

}

/*consumiendo un elemento */

consume_item()

{

printf(“\t\t\t\t't Proc %d consumiendo un item \n”, getpid());

}

/* introduciendo un elemento al almacen */

enter_item()

{

ptg->almacen[ptg->index] = 1;

ptg->index++;

imprime_almacen(“prod”);

}

/* eliminando un elemento del almacen */

remove_item()

{

ptg->index--;

ptg->almacen[ptg->index] = 0;

imprime_almacen(“cons”);

}

/*imprimiendo valores iniciales de los semáforos */

imprime_valores()

{

printf(“\tSemaforo \t\tValor \n”);

printf(“\tmutex:: \t\t%d\n, imp_semval(mutex));

printf(“\tlleno: \t\t%d\n, imp_semval(lleno));

printf(“\tvacio: \t\t%d\n\n, imp_semval(vacio));

}

/*imprimiendo valores almacen y el numero de casillas llenas y v

acías */

imprime_almacen()

{

int j,ct;

ct=0;

printf(“\t\tAlmacen (%s): “,tipo);

printf(“|”);

for (j=0; j<N; j++) {

printf(“%d|”,ptg->almacen[j]);

if ( ptg->almacen[i] )

ct++;

}

printf(“\n\t\t casillas vacias: %d casillas llenas: %d \n”,N-ct,ct);

}

Corrida ejemplo 1

Valores Iniciales Semáforos:

Semáforo Valor

mutex: 1

lleno: 5

vacio: 5

PROCESO CONSUMIDOR PROCESO PRODUCTOR

Empieza ejecución proceso productor 1662

Proc 1662 produciendo un item

Almacen( prod):|1|1|1|1|1|1|0|0|0|0|

casillas vacias: 4 casillas llenas: 6

Empieza ejecucion proceso consumidor 1659

Alamcen( cons):|1|1|1|1|1|0|0|0|0|0|

casillas vacias: 5 casillas llenas: 5

Proc 1659 consumiendo un item

Proc 1662 produciendo un item

Almacen( prod):|1|1|1|1|1|1|0|0|0|0|

casillas vacias: 4 casillas llenas: 6

Alamcen( cons):|1|1|1|1|1|0|0|0|0|0|

casillas vacias: 5 casillas llenas: 5

Proc 1659 consumiendo un item

Proc 1662 produciendo un item

Alamcen(cons):|1|1|1|1|0|0|0|0|0|0|

casillas vacias: 4 casillas llenas: 6

Proc 1659 consumiendo un item

Almacen(prod):|1|1|1|1|1|0|0|0|0|0|

casillas vacias: 5 casillas llenas: 5

Proc 1662 produciendo un item

Valores Iniciales semaforos:

Semáforo Valor

mutesx: 1

lleno: 5

vacio: 5

PROCESO CONSUMIDOR PROCESO PRODUCTOR

Empieza ejecución proceso consumidor 1663

Almacen (cons): |1|1|1|1|1|1|0|0|0|0|

casillas vacias: 6 casillas llenas: 4

Proc 1663 consumiendo un item

Empieza ejecucion proceso productor 1666

Proc 1666 produciendo un item

Almacen: (prod): |1|1|1|1|1|0|0|0|0|0|

casillas vacias: 5 casillas llenas: 5

Almacen: (cons): |1|1|1|1|1|1|0|0|0|0|

casillas vacias: 6 casillas llenas: 4

Proc 1663 consumiendo un item

Almacen: (cons): |1|1|1|0|0|0|0|0|0|0|

casillas vacias: 7 casillas llenas: 3

Proc 1663 consumiendo un item

Proc 1666 produciendo un item

Almacen: (cons): |1|1|0|0|0|0|0|0|0|0|

casillas vacias: 8 casillas llenas: 2

Proc 1663 consumiendo un item

Almacen: (prod): |1|1|1|0|0|0|0|0|0|0|

casillas vacias: 7 casillas llenas: 3

Almacen: (cons): |1|1|0|0|0|0|0|0|0|0|

casillas vacias: 8 casillas llenas: 2

Proc 1663 consumiendo un item

Almaceb (cons): |1|0|0|0|0|0|0|0|0|0|

casillas vacias: 9 casillas llenas: 1

Proc 1663 consumiendo un item

Proc 1666 produciendo un item

Valores Iniciales semaforos:

Semáforo Valor

mutesx: 1

lleno: 5

vacio: 5

PROCESO CONSUMIDOR PROCESO PRODUCTOR

Empieza ejecución proceso productor 1670

Almacen (prod): |1|1|1|1|1|1|0|0|0|0|

casillas vacias: 4 casillas llenas: 6

Empieza ejecucion proceso productor 1667

Almacen: (cons): |1|1|1|1|1|0|0|0|0|0|

casillas vacias: 5 casillas llenas: 5

Proc 1667 consumiendo un item

Proc 1670 produciendo un item

Almacen: (prod): |1|1|1|1|1|1|0|0|0|0|

casillas vacias: 4 casillas llenas: 6

Proc 1670 produciendo un item

Almacen: (prod): |1|1|1|1|1|1|1|0|0|0|

casillas vacias: 3 casillas llenas: 7

Proc 1670 produciendo un item

Almacen: (prod): |1|1|1|1|1|1|1|1|0|0|

casillas vacias: 2 casillas llenas: 8

Almacen: (cons): |1|1|1|1|1|1|1|0|0|0|

casillas vacias: 3 casillas llenas: 7

Proc 1667 consumiendo un item

Proc 1670 produciendo un item

Almacen: (prod): |1|1|1|1|1|1|1|1|0|0|

casillas vacias: 2 casillas llenas: 8

Proc 1670 produciendo un item

Almacen: (prod): |1|1|1|1|1|1|1|1|1|0|

casillas vacias: 1 casillas llenas: 9

Almacen: (cons): |1|1|1|1|1|1|1|1|0|0|

casillas vacias: 2 casillas llenas: 8

Ejemplo2: Hoja de cálculo concurrente

Algoritmo solución

• Memoria compartida: contiene una hoja de cálculo:

+ Ultimo elemento renglón: suma elementos renglón

+ Ultimo elemento columna: suma elementos columna

• Dos procesos:

+ PA: updater

Cambia periódicamente una celda arbitraria a un

valor arbitrario

+ PB: checker

Imprime periódicamente la hoja de calculo,

checa que las sumas estén correctas

Algoritmo updater:

• Escoger una celda y un valor arbitrario

• Escribir el valor arbitrario en la celda escogida

• Calcular y actualizar el total del renglón

• Calcular y actualizar el total de la columna

Algoritmo checker:

• ciclo en todos los renglones:

+ calculo de la suma de todas las celdas del renglón

+ if (sum != total) => printf("Error \n")

• ciclo en todas las columnas:

+ calculo de la suma de todas las celdas de la columna

+ if (sum != total) => printf("Error \n");

Código:

make_random_entry() updater

print_and_check() checker

semop.h funciones manejo semáforos

(make_semas, lock y unlock )

main()

- crea segmento memoria compartido inicalizándolo en cero

- crea los arrglos de semáforos para renglones y columnas

- forks()

- se manda llamar varias veces a la función updater

- se manda llamar varias veces a la función checker

Código del ejemplo

# include<stdio .h>

# include<sys/types.h>

# include<sys/ipc.h>

# include<sys/shm.h >

# include<sys/sem.h>

# include “semop.h”

int totalrow, totalcol ;

int row_ semas, col _semas ;

#define CELL (s, r, c ) ( *(( s ) + (( r ) *NCOLS) + ( c )))

#define NROWS 8

#define NCOLS 8

#define SHEET_KEY 1841

/* ------------------------------ main --------------------------------------*/

main ( )

{

int id, row, col, *sheet ;

totalrow = NROWS -1;

totalcol = NCOLS - 1;

id = shmget (SHEET_KEY, NROWS*NCOLS*sizeof(int) , IPC_CREAT | 0600);

if ( id < 0) {

printF(“Error : falla en el shmget \n”) ;

exit (1) ;

}

sheet = (int * )shmat(id, 0, 0) ;

if (sheet < = ( int *)(0) ) {

printf (“Error : falla en el shmat \n”) ;

exit (2) ;

}

for ( row = 0; row < NROWS; row++)

for (col= 0; col < NCOLS; col++)

CELL(sheet , row, col ) = 0 ;

row_semas = make_semas( SHEET_KEY, NROWS );

col_semas = make_semas( SHEET_KEY+1, NCOLS ) ;

if (( row_semas < 0 ) | | (col_semas < 0 )) {

printf ( “Error : falla en el make_semas \n ) ;

}

if ( fork ( ) ) {

while (1)

print_and_check(sheet) ;

}

else {

while (1)

make_random_entry (sheet) ;

}

}

void make_random_entry( s )

int *s;

{

int row, col, old, new ;

row = rand( ) % (NROWS - 1) ;

col = rand( ) % (NCOLS - 1);

new = rand( ) % 1000 ;

P(row_semas, row) ;

P(col_semas, col) ;

/ * Principio de la SECCION CRITICA */

old = CELL(s, row, col);

CELL(s , row , col ) = new;

CELL(s , row , totalcol ) + = (new - old );

CELL(s , totalrow , col ) + = (new - old);

V(col_semas, col) ;

V(row_semas, row);

/* Fin de la sección crítica */

usleep (5000) ;

}

void print_and_check( s )

int *s ;

{

int row , col ,sum , totalbad ;

static int scount = 0;

totalbad =0 ;

scount ++; /* controlador numero hoja de cálculo */

for ( row = 0 ; row < NROWS ; row ++ ) {

sum = 0;

P(row_semas, row) ; /* Principio de la sección crítica */

for ( col = 0 ; col < NCOLS ; col++) {

if ( col != totalcol)

sum += CELL ( s , row , col );

printf ( “%6d” , CELL(s , row , col )) ;

}

if ( row != totalrow )

totalbad + = (sum !=CELL ( s , row , totalcol )) ;

V(row_semas, row); /* Fin de la sección crítica */

printf ( “\n” ) ;

}

for ( col = 0 ; col < totalcol ; col++ {

sum = 0 ;

P(col_ semas, col) ; /* Principio de la sección crítica */

for ( row = 0; row < totalrow; row++ )

sum += CELL(s, row, col );

totalbad += (sum != CELL (s, totalrow, col)) ;

V(col_semas, col) ; /*Fin de la sección crítica*/

}

if (totalbad)

printf ( “\ n Error hoja de calculo no. %d \n , scount );

if ( ( scount % 10) == 0) /* se imprime cada 10 hojas */

printf ( “\n Hoja calculo no. %d procesada\n” , scount );

printf ( “\n =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n”);

sleep (1) ;

}

Ejemplo de ejecución

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 886 0 0 0 0 886

0 0 0 0 0 0 0 0

0 0 899 0 0 84 0 983

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 2606 0 0 288 0 0

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

480 0 821 933 873 57 834 3998

159 0 342 521 0 0 955 1977

82 262 886 912 0 759 0 2901

0 42 992 719 98 0 781 2632

860 0 69 0 0 182 116 1227

44 0 0 685 734 0 714 2177

0 849 0 0 643 37 351 1880

1625 1153 3110 3875 2348 1850 3751 0

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Estructura de operaciones: sembuf

(qué semáforo, operación, indicador operación)

Objeto de estructura

semid_ds

(control / autorización operaciones)

Objeto de estructura

sem

(valor, procesos esperando)

Arreglo semáforos

struct semid_ds {

struct ipc_perm sem_perm; /* estructura permiso */

int *pad; /* usado por sistema */

ushort sem_nsems; /* número semáforos */

time_t sem_otime; /* tiempo último semop */

time_t sem_ctime; /* tiempo último cambio */

}

struct sembuf{

short sem_num; /* número semáforo */

short sem_op; /* operación semáforo */

short sem_flg; /* parámetro operación*/

}

struct sem {

ushort semval /* valor semáforo */

short sempid /* último proceso que hizo un semop*/

ushort semcnt /* # procesos esperan semval incremente su valor */

ushort semzcnt /* # procesos esperan semval = 0 */

}

Identificador

del arreglo de

semáforos

struct sem

[0]

[0]

[0]

[0]

[2]

[2]

[2]

[2]

[1]

[1]

[1]

[1]

semzcnt

semzcnt

semzcnt

semcnt

semcnt

semcnt

sempid

sempid

sempid

semval

semval

semval

S1

S2

S0

struct semid_ds

sem_ctime

sem_ nsems = 3

sem_otime

structure

sem _perm

pad

Operación a realizar:

valores negativos:

esperar por el semáforo y

apropiarselo (lock)

valores positivos:

liberarlos

sem_flg

sem_op

sem_num

operaciones fancy

generalmente cero

cada elemento del

arreglo es de tipo

struct sembuf

número de

semáforo

número de

operaciones

en el arreglo

arreglo de

operaciones

de semáforo

manejador

semop(id, ops, nops)

struct sem {

ushort semval /* val sem */

short sempid /* último semop*/

ushort semcnt /* incrementar semal */

ushort semzcnt /* semaval = 0 */

}

struct sembuf{

short sem_num; /* número semáforo */

short sem_op; /* operación semáforo */

short sem_flg; /* parámetro* oper. */

}

0: no pasa nada

SEM_UNDO

previene el bloqueo accidental de

semáforos, (proceso muere des-

pués de hacer un P(S) )

IPC_NOWAIT

operaciones no bloqueantes:

devuelve el control en caso de que

no se pueda realizar la operación

especificada en semop( )

struct sembuf{

short sem_num; /* número semáforo */

short sem_op; /* operación semáforo */

short sem_flg; /* parámetro* oper. */

}

struct sem

[0]

[0]

[0]

[0]

struct semid_ds

[2]

[2]

[2]

[2]

[1]

[1]

[1]

[1]

Incrementa el

semáforo en 1

Espera que el

segundo semáforo

sea cero

sem _ flg = 0

struct sembuf oper[2] ={

2,0,0,

2,1,SEM_UNDO }

struct sembuf oper[2];

oper[0].sem_num = 2;

oper[0].sem_ op = 0;

oper[0].sem_flg = 0;

oper[1].sem_num = 2;

oper[1].sem_ op = 1;

oper[1].sem_ flg = SEM_UNDO;

[1]

[1]

[1]

[0]

[0]

[0]

sem_ flg= SEM_UNDO

sem _ op = 1

sem _ num = 2

sem _ num = 2

sem _ op = 0

semop ( id , &oper , 2 )

semzcnt

semzcnt

semzcnt

semcnt

semcnt

semcnt

sempid

sempid

sempid

semval

semval

semval

sem - ctime

sem - nsems = 3

sem - otime

structure

sem - perm

pad

id = semget ( KEY, 3, IPC_CREAT | 0600)

_

_

IPC_RMID

E: modificación valores campos de la es-

tructura de permisos de semid_ds de id,

a partir de lo contenido en arg.buf

-1 si no

y

éxito

tuvo

operación

la

si

0

R:

buf

_

IPC_SET

id, info es almacenada en arg.buf

extracción estructura semid_ds de

E:

no.

si

-1

y

éxito

tuvo

operación

si

0

R:

buf

_

IPC_STAT

primeros semáforos

"sennum"

los

de

inicialización

E:

no.

si

-1

y

éxito

tuvo

operación

si

0

R:

array

semáforos

de

(cantidad),

Número,

SETALL

valor dado

un

a

semáforo

del

inicialización

E:

no.

si

-1

y

éxito

tuvo

operación

si

0

R:

val

número de semáforo

un

de

Especificación

SETVAL

el semáforo

que realizó una operación sobre

proceso

último

del

Identificación

R:

_

número de semáforo

un

de

Especificación

GETPID

"semnum" primeros semáforos

los

de

valores

los

contiene

arreglo

el

E:

no.

si

-1

y

éxito

tuvo

operación

si

0

R:

array

semáforos

de

(cantidad),

Número,

GETALL

R: Valor del semáforo

_

número de semáforo

un

de

Especificación

GETVAL

que el semáforo tome un valor de cero

procesos en espera de

de

Número

R:

_

número de semáforo

un

de

Especificación

GETZCNT

que el semáforo aumente su valor

de

espera

en

procesos

de

Número

R:

_

número de semáforo

un

de

Especificación

GETNCNT

Valor regreso (R), y efecto (E)

Interpretación arg

semnum

operación

semctl(id, semnum, operacion, arg)

Celda

elegida por

update.

Celda no usada para

simplificar el programa.

Arreglo de

semáforos de

renglón.

“locked”

por el

updater

“locked”

por el

checker

“locked”

por el updater

Arreglo de

semáforos de

columna.

7 4 15 9 12 47

3 21 5 2 6 37

8 18 6 1 13 46

20 10 17 6 5 58

38 53 43 18 36

Supresión de la entrada en la tabla de semáforos




Descargar
Enviado por:Sergio Merino Morales
Idioma: castellano
País: Chile

Te va a interesar