#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> ... #define SHMKEY 12 #define SEMKEY 12 #define K 1024 #define XM 20 #define YM 20 #define NUM_SEMAFOROS 1 int shmId, semId; ... char *addr1; typedef struct { // Estructura de los datos a ubicar // en el area compartida int numero1, numero2; char Msg[100][100]; int M[100][100]; } AreaCompartida; AreaCompartida *pAC; struct sembuf psembuf, vsembuf; // // // // void cleanup(); void quienSoy(); Utilizados para definir los comandos para operar en los semaforos main() { ... short initArray[NUM_SEMAFOROS], outArray[NUM_SEMAFOROS]; //1. Captura de señales signal (1, quienSoy); // // signal (2, cleanup); // signal (3, cleanup); // //2. // // // // // // // // // ante señal HUP, el proceso se identificará con estas señales, el proceso terminará Instanciación de un area de memoria compartida entre este proceso y sus procesos hijos: 2.1 Creacion de un area de memoria compartida identificada por el tag SHMKEY (SHMKEY = 12 en este ejemplo) el tamaño es 64K, y podra ser leida y/o escrita por procesos pertenecientes a cualquier usuario (permisos 777 corresp. a u,g,o, respectivamente, interpretados similarmente a los permisos de los archivos de unix shmId = shmget(SHMKEY, 64*K, 0777|IPC_CREAT); 1/3 // // // // 2.2 La instrucción siguiente efectúa el attachment del area compartida recien creada al espacio de memoria de este proceso (y en consecuencia tambien al area de memoria de los procesos hijos de este) addr1 = shmat(shmId, 0, 0); // 2.3 A continuación obtenemos un pointer al primer // elemento del area compartida, para poder nombrarla pAC = (AreaCompartida *) addr1; // // // // 3. Instanciacion de un semaforo 3.1 Creacion de un semaforo que luego usaremos para controlar el acceso a elementos ubicados en el area de memoria compartida semId = semget(SEMKEY, 1, 0777|IPC_CREAT); initArray[0] = 1; // preparo esta variable para // inicializar el valor del // semaforo: "1" significará // "resource unlocked" // 3.2 Inicialización del valor del semaforo (a 1) semctl (semId, 1, SETALL, initArray); // forma de leer el (o los) valor(e)s del semaforo: semctl (semId, 1, GETALL, outArray); printf("Valor inicial del semaforo: [%d]\n", outArray[0] ); // 3.3 Preparar 2 structs para operar sobre el primer // semaforo del array (en este caso, el único) psembuf.sem_num= 0; // primer semaforo del array // la operacion "-1" corresponderá, para nosotros, a la // función de "reservar recurso" psembuf.sem_op= -1; psembuf.sem_flg = SEM_UNDO; vsembuf.sem_num= 0; // primer semaforo del array // la operacion "+1" corresponderá a la función de // "liberar recurso" vsembuf.sem_op= 1; vsembuf.sem_flg = SEM_UNDO; // 4. Creacion de algunos procesos "hijo" childNo = 0; for (j=0; j<XM; j++) // spawn XM hijos { r=random(); k = fork(); if (k==0) execChild(); printf("Se creo proc. child P%d, pid %d.\n", childNo, k); // Parent notifica childNo++; } NoChildren = childNo; childNo=-1; // El proceso parent quedará // identificado con "-1" 2/3 // 5. Loop infinito del proceso parent // (sale mediante algún signal handler) while (1) { printMatrix(1); sleep(1); } } // end main() void cleanup() // Handler de terminación, libera ambas // estructuras (shared mem y semaforo) { shmctl(shmId, IPC_RMID, 0); // destruye shared memory semctl(semId, IPC_RMID, 0); // destruye semaforo printf("Fin del signal handler 'CLEANUP' \n"); exit(); } void quienSoy() // Handler para SIGHUP - el proceso que // la recibe imprime su Id y termina { sprintf(pAC->Msg[childNo], "Yo era P%d\n", childNo); exit(); } execChild() { // Programa básico para los procesos "child", con // ejemplo de locking de recurso compartido int m; while(1) { // 5.1 Obtenemos un "lock" usando el semáforo (primitiva // P de Dijkstra). La primitiva "P" se bloquea hasta que // logra obtener el semáforo (o sea, en este caso, // ponerlo a 0 habiendo estado en 1) semop(semId, &psembuf, 1); // // // // // // // Cuando se sale de P, sabemos que somos los únicos que estamos corriendo con el semáforo en "1" y en consecuencia tenemos el derecho de alterar la memoria compartida (este derecho está acordado cooperativamente entre los procesos que emplean el semáforo, pero no está "garantizado" por el sistema operativo. // 5.2 Alteramos el área de memoria compartida (en este // ejemplo, un elemento de una matriz) m = ++(pAC->M[childNo][childNo]); // // // // // 5.3 Liberamos el lock (operacion "V" de Dijkstra). Al hacerlo, se despierta uno (sólo uno) de los procesos que eventualmente hayan estado esperando por el lock (o sea, que hubieran estado dormidos sobre la primitiva "P", ver 5.1) semop(semId, &vsembuf, 1); } } 3/3