*/
struct Mutex
{
- // Estados para un flag
- /// indica el estado del proceso
- state_t state[2];
- /// el proceso que tiene prioridad ante un race
- int turn;
+ // Estados para un flag
+ /// indica el estado del proceso
+ state_t state[2];
+ /// el proceso que tiene prioridad ante un race
+ int turn;
};
/// Inicializa un mutex
void mutex_init(Mutex& m)
{
- m.state[0] = RELEASED;
- m.state[1] = RELEASED;
- m.turn = 0;
+ m.state[0] = RELEASED;
+ m.state[1] = RELEASED;
+ m.turn = 0;
}
/// Adquiere un mutex para el proceso indicado por nproc
void mutex_acquire(Mutex& m, int proc)
{
- m.state[proc] = ACQUIRED;
- while (m.state[(proc+1)%2] == ACQUIRED)
- {
- if (m.turn != proc)
- {
- m.state[proc] = RELEASED;
- while (m.turn != proc);
- m.state[proc] = ACQUIRED;
- }
- }
+ m.state[proc] = ACQUIRED;
+ while (m.state[(proc+1)%2] == ACQUIRED)
+ {
+ if (m.turn != proc)
+ {
+ m.state[proc] = RELEASED;
+ while (m.turn != proc);
+ m.state[proc] = ACQUIRED;
+ }
+ }
}
/// Libera un mutex para el proceso indicado por proc
void mutex_release(Mutex& m, int proc)
{
- m.turn = (proc+1)%2;
- m.state[proc] = RELEASED;
+ m.turn = (proc+1)%2;
+ m.state[proc] = RELEASED;
}
/**
*/
struct Molinete
{
- unsigned count;
- Mutex mutex;
+ unsigned count;
+ Mutex mutex;
};
/// Inicializa el molinete
void molinete_init(Molinete& m)
{
- m.count = 0;
- mutex_init(m.mutex);
+ m.count = 0;
+ mutex_init(m.mutex);
}
int main(int argc, char *argv[])
{
- using std::cerr;
- using std::cout;
-
- if (argc < 2)
- {
- cerr << "Faltan parametros: " << argv[0] << " (0|1) [max_iter]\n";
- return 1;
- }
- int proc = atoi(argv[1]);
-
- 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";
-
- // Si somos el primer proceso inicializamos el molinete
- if (!proc) molinete_init(*molinete);
-
- // 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;
- mutex_acquire(molinete->mutex, proc);
- if (dec && molinete->count) // Decremento sólo si no es 0
- count = --molinete->count;
- else
- count = ++molinete->count;
- mutex_release(molinete->mutex, proc);
- // 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] << " (0|1) [max_iter]\n";
+ return 1;
+ }
+ int proc = atoi(argv[1]);
+
+ 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";
+
+ // Si somos el primer proceso inicializamos el molinete
+ if (!proc) molinete_init(*molinete);
+ else usleep(1000); // espero que el 1er proceso inicialice
+
+ // Maxima cantidad de iteraciones (puede venir por parametro)
+ int max_iter = 100000;
+ if (argc > 2)
+ max_iter = atoi(argv[2]);
+
+ srand(getpid());
+
+ // Loop principal
+ for (int i = 0; i < max_iter; ++i)
+ {
+ char sdec[] = "sale";
+ char sinc[] = "entra";
+ char* s;
+ bool dec = rand() % 2;
+ int count;
+ mutex_acquire(molinete->mutex, proc);
+ if (dec && molinete->count) // Decremento sólo si no es 0
+ {
+ s = sdec;
+ count = --molinete->count;
+ }
+ else
+ {
+ s = sinc;
+ count = ++molinete->count;
+ }
+ mutex_release(molinete->mutex, proc);
+ // 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 :
/**
* 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 <iostream>
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;
+ 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]);
+ 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";
+ // 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);
- }
+ // 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) // pongo 1 en el sem
+ {
+ 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(10000);
+ }
- // Maxima cantidad de iteraciones (puede venir por parametro)
- int max_iter = 100000;
- if (argc > 2)
- max_iter = atoi(argv[2]);
+ srand(getpid());
- // 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
- }
+ // Maxima cantidad de iteraciones (puede venir por parametro)
+ int max_iter = 100000;
+ if (argc > 2)
+ max_iter = atoi(argv[2]);
- if (shmdt(molinete) == -1)
- {
- cerr << "Error al detachear shared memory.\n";
- return -1;
- }
+ // 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
+ }
- return 0;
+ if (shmdt(molinete) == -1)
+ {
+ cerr << "Error al detachear shared memory.\n";
+ return -1;
+ }
+
+ return 0;
}
+
+// vim: set et sw=4 sts=4 :