]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica2/P02e1101.cpp
9a48aaef191ea4da03ad08549a1d9aea89ab442a
[z.facultad/75.74/practicos.git] / practicas / practica2 / P02e1101.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
16 /// Clave de nuestro segmento shm
17 #define SHM_KEY 0x77891110
18
19 /// Estado de un mutex para un proceso en particular
20 enum state_t { RELEASED, ACQUIRED };
21
22 /**
23  * Estructura de un mutex implementado a través del algoritmo de Decker.
24  */
25 struct Mutex
26 {
27     // Estados para un flag
28     /// indica el estado del proceso
29     state_t state[2];
30     /// el proceso que tiene prioridad ante un race
31     int turn;
32 };
33
34 /// Inicializa un mutex
35 void mutex_init(Mutex& m)
36 {
37     m.state[0] = RELEASED;
38     m.state[1] = RELEASED;
39     m.turn = 0;
40 }
41
42 /// Adquiere un mutex para el proceso indicado por nproc
43 void mutex_acquire(Mutex& m, int proc)
44 {
45     m.state[proc] = ACQUIRED;
46     while (m.state[(proc+1)%2] == ACQUIRED)
47     {
48         if (m.turn != proc)
49         {
50             m.state[proc] = RELEASED;
51             while (m.turn != proc);
52             m.state[proc] = ACQUIRED;
53         }
54     }
55 }
56
57 /// Libera un mutex para el proceso indicado por proc
58 void mutex_release(Mutex& m, int proc)
59 {
60     m.turn = (proc+1)%2;
61     m.state[proc] = RELEASED;
62 }
63
64 /**
65  * Estructura con el contador y su mutex.
66  * Esta estructura será compartida utilizando shared memory.
67  */
68 struct Molinete
69 {
70     unsigned count;
71     Mutex mutex;
72 };
73
74 /// Inicializa el molinete
75 void molinete_init(Molinete& m)
76 {
77     m.count = 0;
78     mutex_init(m.mutex);
79 }
80
81 int main(int argc, char *argv[])
82 {
83     using std::cerr;
84     using std::cout;
85
86     if (argc < 2)
87     {
88         cerr << "Faltan parametros: " << argv[0] << " (0|1) [max_iter]\n";
89         return 1;
90     }
91     int proc = atoi(argv[1]);
92
93     int shm_id;
94     do
95     {
96         shm_id = shmget(SHM_KEY, sizeof(Molinete),
97                 (proc ? 0 : IPC_CREAT) | 0666); // crea solo si es el proceso 0
98     }
99     while (proc != 0 && shm_id == -1);
100     Molinete* molinete = (Molinete*) shmat(shm_id, NULL, 0);
101     if (molinete == (Molinete*) -1)
102     {
103         cerr << "Error al attachear shared memory.\n";
104         return 3;
105     }
106
107     cout << "Shared memory id = " << shm_id << "\n";
108
109     // Si somos el primer proceso inicializamos el molinete
110     if (proc == 0) molinete_init(*molinete);
111
112     // Maxima cantidad de iteraciones (puede venir por parametro)
113     int max_iter = 100;
114     if (argc > 2)
115         max_iter = atoi(argv[2]);
116
117     srand(getpid());
118
119     // Loop principal
120     for (int i = 0; i < max_iter; ++i)
121     {
122         char sdec[] = "sale";
123         char sinc[] = "entra";
124         char* s;
125         bool dec = rand() % 2;
126         int count;
127         mutex_acquire(molinete->mutex, proc);
128         if (dec && molinete->count) // Decremento sólo si no es 0
129         {
130             s = sdec;
131             count = --molinete->count;
132         }
133         else
134         {
135             s = sinc;
136             count = ++molinete->count;
137         }
138         mutex_release(molinete->mutex, proc);
139         // Uso cout directamente porque es line-buffered, mientras que
140         // no use threads no es problema el buffer de cout. Y de todas
141         // formas pongo un flush (el endl es \n+flush) por las dudas.
142         cout << "Proceso " << proc << " (" << s << "): molinete = " << count
143                 << std::endl;
144         sched_yield(); // Para ver como se entrelazan mejor
145     }
146
147     if (shmdt(molinete) == -1)
148     {
149         cerr << "Error al detachear shared memory.\n";
150         return -1;
151     }
152
153     return 0;
154 }
155
156 // vim: set et sw=4 sts=4 :