X-Git-Url: https://git.llucax.com/z.facultad/75.74/practicos.git/blobdiff_plain/6d12425d217477390d8772843d167e9d31d7cc19..89195ca63ae56eeb2463b061ab32f5c7acbb71f9:/practicas/practica2/P02e1201.cpp diff --git a/practicas/practica2/P02e1201.cpp b/practicas/practica2/P02e1201.cpp index 24e3f63..c730202 100644 --- a/practicas/practica2/P02e1201.cpp +++ b/practicas/practica2/P02e1201.cpp @@ -1,8 +1,8 @@ /** * Leandro Lucarella (77891) * - * Ejercicio 1.1. Implementa problema del museo usando solamente variables - * (shared memory) + * Ejercicio 1.2. Implementa problema del museo usando variables (shared memory) + * y semaforos. */ #include @@ -21,109 +21,124 @@ /// Ahora el contador es un simple unsigned typedef unsigned Molinete; -/// Union para utilizar semaforo -union semun +/// Hace un wait (P) al semaforo (devuelve false si hubo error). +void sem_wait(int sem_id) { - int val; - struct semid_ds* buf; - unsigned short* array; -}; + struct sembuf op; + op.sem_op = -1; // sacar 1 + op.sem_num = 0; // al semaforo 1 + op.sem_flg = 0; // esperando + if (semop(sem_id, &op, 1) < 0) + { + std::cerr << "No se pudo sacar al semaforo.\n"; + exit(100); + } +} + +/// Hace un signal (V) al semaforo (devuelve false si hubo error). +void sem_signal(int sem_id) +{ + struct sembuf op; + op.sem_op = 1; // agregar 1 + op.sem_num = 0; // al semaforo 1 + op.sem_flg = 0; // esperando + if (semop(sem_id, &op, 1) < 0) + { + std::cerr << "No se pudo poner en el semaforo.\n"; + exit(101); + } +} int main(int argc, char *argv[]) { - using std::cerr; - using std::cout; - - if (argc < 2) - { - cerr << "Faltan parametros: " << argv[0] << " N [max_iter]\n"; - return 1; - } - int proc = atoi(argv[1]); - - // Shared memory - int shm_id = shmget(SHM_KEY, sizeof(Molinete), IPC_CREAT | 0666); - if (shm_id == -1) - { - cerr << "Error al crea/obtener shared memory.\n"; - return 2; - } - Molinete* molinete = (Molinete*) shmat(shm_id, NULL, 0); - if (molinete == (Molinete*) -1) - { - cerr << "Error al attachear shared memory.\n"; - return 3; - } - cout << "Shared memory id = " << shm_id << "\n"; - - // Semaforo - int sem_id = semget(SEM_KEY, 1, 0666 | IPC_CREAT); - if (sem_id == -1) - { - cerr << "Error al crea/obtener semaforo.\n"; - return 4; - } - semun sem_arg; - sem_arg.val = 0; - if (semctl(sem_id, 0, SETVAL, sem_arg) < 0) - { - cerr << "No se pudo inicializar semaforo.\n"; - return 5; - } - struct sembuf ops; - ops.sem_op = 1; // agregar 1 - ops.sem_num = 0; // al semaforo 1 - ops.sem_flg = 0; // esperando - if (semop(sem_id, &ops, 1) < 0) - { - cerr << "No se pudo agregar al semaforo.\n"; - return 6; - } - cout << "Semaforo inicializado id = " << sem_id << "\n"; - - // Si somos el primer proceso inicializamos el molinete - if (!proc) *molinete = 0; - - // Maxima cantidad de iteraciones (puede venir por parametro) - int max_iter = 100000; - if (argc > 2) - max_iter = atoi(argv[2]); - - // Loop principal - for (int i = 0; i < max_iter; ++i) - { - bool dec = rand() % 2; - int count; - // lock - ops.sem_op = -1; // saco 1 (== adquirir el mutex) - if (semop(sem_id, &ops, 1) < 0) - { - cerr << "No se pudo sacar al semaforo.\n"; - return 6; - } - if (dec && molinete) // Decremento sólo si no es 0 - count = --*molinete; - else - count = ++*molinete; - // unlock - ops.sem_op = 1; // pongo 1 (== liberar el mutex) - if (semop(sem_id, &ops, 1) < 0) - { - cerr << "No se pudo sacar al semaforo.\n"; - return 6; - } - // Uso cout directamente porque es line-buffered, mientras que - // no use threads no es problema el buffer de cout. Y de todas - // formas pongo un flush (el endl es \n+flush) por las dudas. - cout << "Proceso " << proc << ": molinete = " << count << std::endl; - //sched_yield(); // Para ver como se entrelazan mejor - } - - if (shmdt(molinete) == -1) - { - cerr << "Error al detachear shared memory.\n"; - return -1; - } - - return 0; + using std::cerr; + using std::cout; + + if (argc < 2) + { + cerr << "Faltan parametros: " << argv[0] << " N [max_iter]\n"; + return 1; + } + int proc = atoi(argv[1]); + + // Shared memory + int shm_id; + do + { + shm_id = shmget(SHM_KEY, sizeof(Molinete), + (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0 + } + while (proc != 0 && shm_id == -1); + Molinete* molinete = (Molinete*) shmat(shm_id, NULL, 0); + if (molinete == (Molinete*) -1) + { + cerr << "Error al attachear shared memory.\n"; + return 3; + } + + // Semaforo + int sem_id; + do + { + sem_id = semget(SEM_KEY, 1, + (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0 + } + while (proc != 0 && sem_id == -1); + + // Si es el primero, inicializo + if (proc == 0) + { + *molinete = 0; + if (semctl(sem_id, 0, SETVAL, 1) < 0) // pongo 1 en el sem + { + cerr << "No se pudo inicializar semaforo.\n"; + return 5; + } + cout << "Semaforo inicializado id = " << sem_id << "\n"; + } + + srand(getpid()); + + // Maxima cantidad de iteraciones (puede venir por parametro) + int max_iter = 100; + if (argc > 2) + max_iter = atoi(argv[2]); + + // Loop principal + for (int i = 0; i < max_iter; ++i) + { + char sdec[] = "sale"; + char sinc[] = "entra"; + char* s; + bool dec = rand() % 2; + int count; + sem_wait(sem_id); // lock + if (dec && *molinete) // Decremento sólo si no es 0 + { + s = sdec; + count = --*molinete; + } + else + { + s = sinc; + count = ++*molinete; + } + sem_signal(sem_id); // unlock + // Uso cout directamente porque es line-buffered, mientras que + // no use threads no es problema el buffer de cout. Y de todas + // formas pongo un flush (el endl es \n+flush) por las dudas. + cout << "Proceso " << proc << " (" << s << "): molinete = " << count + << std::endl; + sched_yield(); // Para ver como se entrelazan mejor + } + + if (shmdt(molinete) == -1) + { + cerr << "Error al detachear shared memory.\n"; + return -1; + } + + return 0; } + +// vim: set et sw=4 sts=4 :