]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica2/P02e2121.cpp
Se hace que se imprima info de debug solo para DEBUG2.
[z.facultad/75.74/practicos.git] / practicas / practica2 / P02e2121.cpp
1 /**
2  * Leandro Lucarella (77891)
3  *
4  * Ejercicio 2.1.2. Implementa productor-consumidor con semaforos binarios y
5  * shared memory pero con 3 productores que producen 1/3 cada uno.
6  */
7
8 #include <iostream>
9 #include <cstdlib>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/types.h>
13 #include <sys/ipc.h>
14 #include <sys/shm.h>
15 #include <sys/sem.h>
16
17 using std::cerr;
18 using std::cout;
19 using std::endl;
20
21 /// Clave de nuestro segmento shm y semaforo
22 #define SHM_KEY 0x77891222
23 #define SEM_KEY 0x77891223
24
25 /// Maxima cantidad de partes y consumidores
26 #define MAX_PARTES 3
27 #define MAX_CONSUM 2
28
29 /// Elemento a producir/consumir
30 struct Elemento
31 {
32     int partes[MAX_PARTES];     ///> Partes del producto a producir
33     bool producido[MAX_PARTES]; ///> Indica que parte fue producida
34     bool consumido[MAX_CONSUM]; ///> Indica quien consumio
35 };
36
37 /// Inicializa elemento
38 void elemento_init(Elemento* e)
39 {
40     e->producido[0] = e->producido[1] = e->producido[2] = false;
41     e->consumido[0] = e->consumido[1] = false;
42 }
43
44 /// Nombres de los semaforos a utilizar
45 enum sem_num_t { MUTEX, FULL, EMPTY };
46
47 /// Nombres de los procesos
48 enum proc_t { PRODUCTOR1, PRODUCTOR2, PRODUCTOR3, CONSUMIDOR1, CONSUMIDOR2 };
49
50 void sem_init(int sem_id, sem_num_t sem_num, int val)
51 {
52     if (semctl(sem_id, sem_num, SETVAL, val) < 0)
53     {
54         cerr << "No se pudo inicializar semaforo.\n";
55         exit(99);
56     }
57 }
58
59
60 /// Hace un wait (P) al semaforo (devuelve false si hubo error).
61 void sem_wait(int sem_id, sem_num_t sem_num)
62 {
63     struct sembuf op;
64     op.sem_op = -1; // sacar 1
65     op.sem_num = sem_num; // al semaforo sem_num
66     op.sem_flg = 0; // esperando
67     if (semop(sem_id, &op, 1) > 0)
68     {
69         cerr << "No se pudo sacar al semaforo.\n";
70         exit(100);
71     }
72 }
73
74 /// Hace un signal (V) al semaforo (devuelve false si hubo error).
75 void sem_signal(int sem_id, sem_num_t sem_num)
76 {
77     struct sembuf op;
78     op.sem_op =  1; // agregar 1
79     op.sem_num = sem_num; // al semaforo sem_num
80     op.sem_flg = 0; // esperando
81     if (semop(sem_id, &op, 1) > 0)
82     {
83         cerr << "No se pudo poner al semaforo.\n";
84         exit(101);
85     }
86 }
87
88 void producir(int proc, int parte, int sem_id, Elemento* elem, int iter)
89 {
90     for (int i = 0; i < iter; ++i)
91     {
92         int val = rand();
93         sem_wait(sem_id, EMPTY); // espera que este vacio (que hayan leido los 2)
94         sem_wait(sem_id, MUTEX); // lock
95         // produzco mi parte
96         if (!elem->producido[parte])
97         {
98             elem->partes[parte] = val;
99             elem->producido[parte] = true;
100             cout << "Productor " << parte << " puso su parte: " << val << endl;
101         }
102         else
103             --i; // no cuento esta iteración
104         // si esta todo listo, aviso
105         if (elem->producido[0] && elem->producido[1] && elem->producido[2])
106         {
107             elem->consumido[0] = elem->consumido[1] = false;
108             sem_signal(sem_id, MUTEX); // unlock
109             sem_signal(sem_id, FULL);
110         }
111         else
112         {
113             sem_signal(sem_id, MUTEX); // unlock
114             sem_signal(sem_id, EMPTY);
115         }
116     }
117 }
118
119 void consumir(int proc, int consumidor, int sem_id, Elemento* elem, int iter)
120 {
121     for (int i = 0; i < iter; ++i)
122     {
123         sem_wait(sem_id, FULL); // espera que este lleno
124         sem_wait(sem_id, MUTEX); // lock
125         // consumo
126         if (!elem->consumido[consumidor])
127         {
128             elem->consumido[consumidor] = true;
129             cout << "Consumidor " << consumidor << " consumio "
130                 << elem->partes[0] << "," << elem->partes[1]
131                 << "," << elem->partes[2] << endl;
132         }
133         else
134             --i; // no cuento esta iteracion
135         // si esta todo listo, aviso
136         if (elem->consumido[0] && elem->consumido[1])
137         {
138             elem->producido[0] = elem->producido[1]
139                 = elem->producido[2] = false;
140             sem_signal(sem_id, MUTEX); // unlock
141             sem_signal(sem_id, EMPTY);
142         }
143         else
144         {
145             sem_signal(sem_id, MUTEX); // unlock
146             sem_signal(sem_id, FULL);
147         }
148     }
149 }
150
151 int main(int argc, char *argv[])
152 {
153     if (argc < 2)
154     {
155         cerr << "Faltan parametros: " << argv[0] << " N [max_iter]\n";
156         return 1;
157     }
158     proc_t proc = (proc_t) atoi(argv[1]);
159
160     // Shared memory
161     int shm_id;
162     do
163     {
164         shm_id = shmget(SHM_KEY, sizeof(Elemento),
165             (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0
166     }
167     while (proc != PRODUCTOR1 && shm_id == -1);
168     Elemento* elem = (Elemento*) shmat(shm_id, NULL, 0);
169     if (elem == (Elemento*) -1)
170     {
171         cerr << "Error al attachear shared memory.\n";
172         return 3;
173     }
174
175     // Semaforos
176     int sem_id;
177     do
178     {
179         sem_id = semget(SEM_KEY, 3,
180             (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0
181     }
182     while (proc != PRODUCTOR1 && sem_id == -1);
183
184     // Si somos los primeros inicializamos
185     if (proc == PRODUCTOR1)
186     {
187         elemento_init(elem);
188         sem_init(sem_id, MUTEX, 1);
189         sem_init(sem_id, FULL, 0);
190         sem_init(sem_id, EMPTY, 1);
191     }
192
193     srand(getpid());
194
195     // Maxima cantidad de iteraciones (puede venir por parametro)
196     int max_iter = 10;
197     if (argc > 2)
198         max_iter = atoi(argv[2]);
199
200     if (proc < 3) // es productor
201         producir(proc, proc, sem_id, elem, max_iter);
202     else // consumidor
203         consumir(proc, proc-3, sem_id, elem, max_iter);
204
205     if (shmdt(elem) == -1)
206     {
207         cerr << "Error al detachear shared memory.\n";
208         return -1;
209     }
210
211     return 0;
212 }
213
214 // vim: set et sw=4 sts=4 :