]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica2/P02e1201.cpp
9c0cb6b255495ea65e7390bf9aa2bca417b84ed2
[z.facultad/75.74/practicos.git] / practicas / practica2 / P02e1201.cpp
1 /**
2  * Leandro Lucarella (77891)
3  *
4  * Ejercicio 1.1. Implementa problema del museo usando solamente variables
5  * (shared memory)
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 /// Clave de nuestro segmento shm y semaforo
18 #define SHM_KEY 0x77891120
19 #define SEM_KEY 0x77891121
20
21 /// Ahora el contador es un simple unsigned
22 typedef unsigned Molinete;
23
24 /// Hace un wait (P) al semaforo (devuelve false si hubo error).
25 bool sem_wait(int sem_id)
26 {
27         struct sembuf op;
28         op.sem_op = -1; // sacar 1
29         op.sem_num = 0; // al semaforo 1
30         op.sem_flg = 0; // esperando
31         return semop(sem_id, &op, 1) >= 0;
32 }
33
34 /// Hace un signal (V) al semaforo (devuelve false si hubo error).
35 bool sem_signal(int sem_id)
36 {
37         struct sembuf op;
38         op.sem_op =  1; // agregar 1
39         op.sem_num = 0; // al semaforo 1
40         op.sem_flg = 0; // esperando
41         return semop(sem_id, &op, 1) >= 0;
42 }
43
44 int main(int argc, char *argv[])
45 {
46         using std::cerr;
47         using std::cout;
48
49         if (argc < 2)
50         {
51                 cerr << "Faltan parametros: " << argv[0] << " N [max_iter]\n";
52                 return 1;
53         }
54         int proc = atoi(argv[1]);
55
56         // Shared memory
57         int shm_id = shmget(SHM_KEY, sizeof(Molinete), IPC_CREAT | 0666);
58         if (shm_id == -1)
59         {
60                 cerr << "Error al crea/obtener shared memory.\n";
61                 return 2;
62         }
63         Molinete* molinete = (Molinete*) shmat(shm_id, NULL, 0);
64         if (molinete == (Molinete*) -1)
65         {
66                 cerr << "Error al attachear shared memory.\n";
67                 return 3;
68         }
69         cout << "Shared memory id = " << shm_id << "\n";
70
71         // Semaforo
72         int sem_id = semget(SEM_KEY, 1, 0666 | IPC_CREAT);
73         if (sem_id == -1)
74         {
75                 cerr << "Error al crea/obtener semaforo.\n";
76                 return 4;
77         }
78         // Si es el primero, inicializo
79         if (!proc)
80         {
81                 *molinete = 0;
82                 if (semctl(sem_id, 0, SETVAL, 1) < 0)
83                 {
84                         cerr << "No se pudo inicializar semaforo.\n";
85                         return 5;
86                 }
87                 cout << "Semaforo inicializado id = " << sem_id << "\n";
88         }
89         else // Si soy otro espero un poco por las dudas para que corra el 1ro
90         {
91                 usleep(1000);
92         }
93
94         // Maxima cantidad de iteraciones (puede venir por parametro)
95         int max_iter = 100000;
96         if (argc > 2)
97                 max_iter = atoi(argv[2]);
98
99         // Loop principal
100         for (int i = 0; i < max_iter; ++i)
101         {
102                 bool dec = rand() % 2;
103                 int count;
104                 if (!sem_wait(sem_id)) // lock
105                 {
106                         cerr << "No se pudo sacar al semaforo.\n";
107                         return 6;
108                 }
109                 if (dec && *molinete) // Decremento sólo si no es 0
110                         count = --*molinete;
111                 else
112                         count = ++*molinete;
113                 if (!sem_signal(sem_id)) // unlock
114                 {
115                         cerr << "No se pudo sacar al semaforo.\n";
116                         return 6;
117                 }
118                 // Uso cout directamente porque es line-buffered, mientras que
119                 // no use threads no es problema el buffer de cout. Y de todas
120                 // formas pongo un flush (el endl es \n+flush) por las dudas.
121                 cout << "Proceso " << proc << ": molinete = " << count << std::endl;
122                 //sched_yield(); // Para ver como se entrelazan mejor
123         }
124
125         if (shmdt(molinete) == -1)
126         {
127                 cerr << "Error al detachear shared memory.\n";
128                 return -1;
129         }
130
131         return 0;
132 }