]> git.llucax.com Git - z.facultad/75.74/practicos.git/commitdiff
Terminado 2.1.2 (con mucha bussy wait pero funciona).
authorLeandro Lucarella <llucax@gmail.com>
Mon, 24 Apr 2006 04:40:58 +0000 (04:40 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Mon, 24 Apr 2006 04:40:58 +0000 (04:40 +0000)
practicas/practica2/P02e2121.cpp [new file with mode: 0644]
practicas/practica2/P02e2121.sh [new file with mode: 0755]

diff --git a/practicas/practica2/P02e2121.cpp b/practicas/practica2/P02e2121.cpp
new file mode 100644 (file)
index 0000000..7aedaec
--- /dev/null
@@ -0,0 +1,214 @@
+/**
+ * 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 :
diff --git a/practicas/practica2/P02e2121.sh b/practicas/practica2/P02e2121.sh
new file mode 100755 (executable)
index 0000000..a83df57
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Lanzo procesos
+# Productores
+./P02e2121 0 $1 &
+p0=$!
+./P02e2121 1 $1 &
+p1=$!
+./P02e2121 2 $1 &
+p2=$!
+# Consumidores
+./P02e2121 3 $1 &
+p3=$!
+./P02e2121 4 $1 &
+p4=$!
+
+# Espero que terminen
+wait $p0
+wait $p01
+wait $p02
+wait $p03
+wait $p04
+
+# Limpio IPC
+ipcrm -M 0x77891222
+ipcrm -S 0x77891223