X-Git-Url: https://git.llucax.com/z.facultad/75.74/practicos.git/blobdiff_plain/eed78fbb7c396cd3be666be8f2517bb828ae1353..51f24d14e8c4c52776a98c8e2aaacf95f90ad1f4:/practicas/practica2/P02e1201.cpp?ds=sidebyside diff --git a/practicas/practica2/P02e1201.cpp b/practicas/practica2/P02e1201.cpp index 9c0cb6b..5600630 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 @@ -22,111 +22,122 @@ typedef unsigned Molinete; /// Hace un wait (P) al semaforo (devuelve false si hubo error). -bool sem_wait(int sem_id) +void sem_wait(int sem_id) { - struct sembuf op; - op.sem_op = -1; // sacar 1 - op.sem_num = 0; // al semaforo 1 - op.sem_flg = 0; // esperando - return semop(sem_id, &op, 1) >= 0; + 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). -bool sem_signal(int sem_id) +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 - return semop(sem_id, &op, 1) >= 0; + 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; - } - // Si es el primero, inicializo - if (!proc) - { - *molinete = 0; - if (semctl(sem_id, 0, SETVAL, 1) < 0) - { - cerr << "No se pudo inicializar semaforo.\n"; - return 5; - } - cout << "Semaforo inicializado id = " << sem_id << "\n"; - } - else // Si soy otro espero un poco por las dudas para que corra el 1ro - { - usleep(1000); - } - - // 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; - if (!sem_wait(sem_id)) // lock - { - 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; - if (!sem_signal(sem_id)) // unlock - { - 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; + } + } + + srand(getpid()); + + // Maxima cantidad de iteraciones (puede venir por parametro) + int max_iter = 10; + 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 :