--- /dev/null
+/**
+ * Leandro Lucarella (77891)
+ *
+ * Ejercicio 2.1.2. Implementa productor-consumidor con semaforos binarios y
+ * shared memory pero con 3 productores que producen 1/3 cada uno.
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+/// Clave de nuestro segmento shm y semaforo
+#define SHM_KEY 0x77891222
+#define SEM_KEY 0x77891223
+
+/// Maxima cantidad de partes y consumidores
+#define MAX_PARTES 3
+#define MAX_CONSUM 2
+
+/// Elemento a producir/consumir
+struct Elemento
+{
+ int partes[MAX_PARTES]; ///> Partes del producto a producir
+ bool producido[MAX_PARTES]; ///> Indica que parte fue producida
+ bool consumido[MAX_CONSUM]; ///> Indica quien consumio
+};
+
+/// Inicializa elemento
+void elemento_init(Elemento* e)
+{
+ e->producido[0] = e->producido[1] = e->producido[2] = false;
+ e->consumido[0] = e->consumido[1] = false;
+}
+
+/// Nombres de los semaforos a utilizar
+enum sem_num_t { MUTEX, FULL, EMPTY };
+
+/// Nombres de los procesos
+enum proc_t { PRODUCTOR1, PRODUCTOR2, PRODUCTOR3, CONSUMIDOR1, CONSUMIDOR2 };
+
+void sem_init(int sem_id, sem_num_t sem_num, int val)
+{
+ if (semctl(sem_id, sem_num, SETVAL, val) < 0)
+ {
+ cerr << "No se pudo inicializar semaforo.\n";
+ exit(99);
+ }
+}
+
+
+/// Hace un wait (P) al semaforo (devuelve false si hubo error).
+void sem_wait(int sem_id, sem_num_t sem_num)
+{
+ struct sembuf op;
+ op.sem_op = -1; // sacar 1
+ op.sem_num = sem_num; // al semaforo sem_num
+ op.sem_flg = 0; // esperando
+ if (semop(sem_id, &op, 1) > 0)
+ {
+ 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, sem_num_t sem_num)
+{
+ struct sembuf op;
+ op.sem_op = 1; // agregar 1
+ op.sem_num = sem_num; // al semaforo sem_num
+ op.sem_flg = 0; // esperando
+ if (semop(sem_id, &op, 1) > 0)
+ {
+ cerr << "No se pudo poner al semaforo.\n";
+ exit(101);
+ }
+}
+
+void producir(int proc, int parte, int sem_id, Elemento* elem, int iter)
+{
+ for (int i = 0; i < iter; ++i)
+ {
+ int val = rand();
+ sem_wait(sem_id, EMPTY); // espera que este vacio (que hayan leido los 2)
+ sem_wait(sem_id, MUTEX); // lock
+ // produzco mi parte
+ if (!elem->producido[parte])
+ {
+ elem->partes[parte] = val;
+ elem->producido[parte] = true;
+ cout << "Productor " << parte << " puso su parte: " << val << endl;
+ }
+ else
+ --i; // no cuento esta iteración
+ // si esta todo listo, aviso
+ if (elem->producido[0] && elem->producido[1] && elem->producido[2])
+ {
+ elem->consumido[0] = elem->consumido[1] = false;
+ sem_signal(sem_id, MUTEX); // unlock
+ sem_signal(sem_id, FULL);
+ }
+ else
+ {
+ sem_signal(sem_id, MUTEX); // unlock
+ sem_signal(sem_id, EMPTY);
+ }
+ }
+}
+
+void consumir(int proc, int consumidor, int sem_id, Elemento* elem, int iter)
+{
+ for (int i = 0; i < iter; ++i)
+ {
+ sem_wait(sem_id, FULL); // espera que este lleno
+ sem_wait(sem_id, MUTEX); // lock
+ // consumo
+ if (!elem->consumido[consumidor])
+ {
+ elem->consumido[consumidor] = true;
+ cout << "Consumidor " << consumidor << " consumio "
+ << elem->partes[0] << "," << elem->partes[1]
+ << "," << elem->partes[2] << endl;
+ }
+ else
+ --i; // no cuento esta iteracion
+ // si esta todo listo, aviso
+ if (elem->consumido[0] && elem->consumido[1])
+ {
+ elem->producido[0] = elem->producido[1]
+ = elem->producido[2] = false;
+ sem_signal(sem_id, MUTEX); // unlock
+ sem_signal(sem_id, EMPTY);
+ }
+ else
+ {
+ sem_signal(sem_id, MUTEX); // unlock
+ sem_signal(sem_id, FULL);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ cerr << "Faltan parametros: " << argv[0] << " N [max_iter]\n";
+ return 1;
+ }
+ proc_t proc = (proc_t) atoi(argv[1]);
+
+ // Shared memory
+ int shm_id;
+ do
+ {
+ shm_id = shmget(SHM_KEY, sizeof(Elemento),
+ (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0
+ }
+ while (proc != PRODUCTOR1 && shm_id == -1);
+ Elemento* elem = (Elemento*) shmat(shm_id, NULL, 0);
+ if (elem == (Elemento*) -1)
+ {
+ cerr << "Error al attachear shared memory.\n";
+ return 3;
+ }
+
+ // Semaforos
+ int sem_id;
+ do
+ {
+ sem_id = semget(SEM_KEY, 3,
+ (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0
+ }
+ while (proc != PRODUCTOR1 && sem_id == -1);
+
+ // Si somos los primeros inicializamos
+ if (proc == PRODUCTOR1)
+ {
+ elemento_init(elem);
+ sem_init(sem_id, MUTEX, 1);
+ sem_init(sem_id, FULL, 0);
+ sem_init(sem_id, EMPTY, 1);
+ }
+
+ srand(getpid());
+
+ // Maxima cantidad de iteraciones (puede venir por parametro)
+ int max_iter = 10;
+ if (argc > 2)
+ max_iter = atoi(argv[2]);
+
+ if (proc < 3) // es productor
+ producir(proc, proc, sem_id, elem, max_iter);
+ else // consumidor
+ consumir(proc, proc-3, sem_id, elem, max_iter);
+
+ if (shmdt(elem) == -1)
+ {
+ cerr << "Error al detachear shared memory.\n";
+ return -1;
+ }
+
+ return 0;
+}
+
+// vim: set et sw=4 sts=4 :