]> git.llucax.com Git - z.facultad/75.74/practicos.git/blob - practicas/practica2/P02e1101.cpp
Completo 2.1.1 y arreglo 1.2.
[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 = shmget(SHM_KEY, sizeof(Molinete), IPC_CREAT | 0666);
94         if (shm_id == -1)
95         {
96                 cerr << "Error al crea/obtener shared memory.\n";
97                 return 2;
98         }
99         Molinete* molinete = (Molinete*) shmat(shm_id, NULL, 0);
100         if (molinete == (Molinete*) -1)
101         {
102                 cerr << "Error al attachear shared memory.\n";
103                 return 3;
104         }
105
106         cout << "Shared memory id = " << shm_id << "\n";
107
108         // Si somos el primer proceso inicializamos el molinete
109         if (!proc) molinete_init(*molinete);
110
111         // Maxima cantidad de iteraciones (puede venir por parametro)
112         int max_iter = 100000;
113         if (argc > 2)
114                 max_iter = atoi(argv[2]);
115
116         // Loop principal
117         for (int i = 0; i < max_iter; ++i)
118         {
119                 bool dec = rand() % 2;
120                 int count;
121                 mutex_acquire(molinete->mutex, proc);
122                 if (dec && molinete->count) // Decremento sólo si no es 0
123                         count = --molinete->count;
124                 else
125                         count = ++molinete->count;
126                 mutex_release(molinete->mutex, proc);
127                 // Uso cout directamente porque es line-buffered, mientras que
128                 // no use threads no es problema el buffer de cout. Y de todas
129                 // formas pongo un flush (el endl es \n+flush) por las dudas.
130                 cout << "Proceso " << proc << ": molinete = " << count << std::endl;
131                 //sched_yield(); // Para ver como se entrelazan mejor
132         }
133
134         if (shmdt(molinete) == -1)
135         {
136                 cerr << "Error al detachear shared memory.\n";
137                 return -1;
138         }
139
140         return 0;
141 }