]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica2/P02e1101.cpp
Bugfix de documentación.
[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     // Si somos el primer proceso inicializamos el molinete
108     if (proc == 0) molinete_init(*molinete);
109
110     // Maxima cantidad de iteraciones (puede venir por parametro)
111     int max_iter = 100;
112     if (argc > 2)
113         max_iter = atoi(argv[2]);
114
115     srand(getpid());
116
117     // Loop principal
118     for (int i = 0; i < max_iter; ++i)
119     {
120         char sdec[] = "sale";
121         char sinc[] = "entra";
122         char* s;
123         bool dec = rand() % 2;
124         int count;
125         mutex_acquire(molinete->mutex, proc);
126         if (dec && molinete->count) // Decremento sólo si no es 0
127         {
128             s = sdec;
129             count = --molinete->count;
130         }
131         else
132         {
133             s = sinc;
134             count = ++molinete->count;
135         }
136         mutex_release(molinete->mutex, proc);
137         // Uso cout directamente porque es line-buffered, mientras que
138         // no use threads no es problema el buffer de cout. Y de todas
139         // formas pongo un flush (el endl es \n+flush) por las dudas.
140         cout << "Proceso " << proc << " (" << s << "): molinete = " << count
141                 << std::endl;
142         sched_yield(); // Para ver como se entrelazan mejor
143     }
144
145     if (shmdt(molinete) == -1)
146     {
147         cerr << "Error al detachear shared memory.\n";
148         return -1;
149     }
150
151     return 0;
152 }
153
154 // vim: set et sw=4 sts=4 :