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