-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproblem_4.c
312 lines (247 loc) · 15.4 KB
/
problem_4.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#include <stdio.h>
#include <pthread.h> // Biblioteca para suporte a threads em C.
#include <unistd.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h> // Biblioteca para manipulação de tempo.
#include <Windows.h>
#define NUM_CARROS 120 // Define o número de carros na simulação.
#define NUM_CAMINHOES 10 // Define o número de caminhões na simulação.
#define MAX_TEMPO_CHEGADA 3 // Define o tempo máximo de chegada dos veículos.
#define TEMPO_TRAVESSIA_CARRO 5 // Define o tempo de travessia de um carro.
#define TEMPO_TRAVESSIA_CAMINHAO 10 // Define o tempo de travessia de um caminhão.
#define TEMPO_TRAVESSIA_CARRO_ANTIGA 4 // Define o tempo de travessia de um carro na ponte antiga.
#define TEMPO_ESPACO 1 // Define o intervalo entre os veículos.
#define TEMPO_ESPACO_ANTIGA 2 // Define o intervalo entre os veículos na ponte antiga.
#define MAX_CARROS_PONTE 5 // Define o número máximo de carros que podem estar na ponte ao mesmo tempo.
#define MAX_CARROS_PONTE_ANTIGA 2 // Define o número máximo de carros que podem estar na ponte antiga ao mesmo tempo.
#define MAX_CAMINHAO_PONTE 1 // Define o número máximo de caminhões que podem estar na ponte ao mesmo tempo.
// Inicialização de mutex e variáveis de condição para controle de concorrência.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_carro[2] = {PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER};
pthread_cond_t cond_caminhao[2] = {PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER};
pthread_cond_t cond_carro_antiga[2] = {PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER};
// Declaração de variáveis globais para controlar o estado da ponte e coletar estatísticas.
int carros_na_ponte = 0;
int caminhoes_na_ponte = 0;
int carros_na_ponte_antiga = 0;
int direcao_na_ponte = -1; // -1: ninguém na ponte, 0: direção 0, 1: direção 1
int direcao_na_ponte_antiga = -1; // -1: ninguém na ponte, 0: direção 0, 1: direção 1
// Variáveis para rastrear a quantidade de veículos antes de trocar o sentido.
int contador_carros_mesmo_sentido = 0;
int contador_caminhoes_mesmo_sentido = 0;
int contador_carros_mesmo_sentido_antiga = 0;
// Estatísticas de carros.
int tempo_max_espera_carros = 0;
int tempo_min_espera_carros = INT_MAX;
double tempo_total_espera_carros = 0;
int carros_por_direcao[2] = {0, 0};
// Estatísticas de caminhões.
int tempo_max_espera_caminhoes = 0;
int tempo_min_espera_caminhoes = INT_MAX;
double tempo_total_espera_caminhoes = 0;
int caminhoes_por_direcao[2] = {0, 0};
// Estatísticas da ponte.
int tempo_total_execucao;
int tempo_total_ocupado = 0;
int ponte_ocupada = -1;
// Estatísticas da ponte antiga.
int tempo_total_ocupado_antiga = 0;
int ponte_antiga_ocupada = -1;
// Função que será executada por cada thread (carro).
void *carro(void *arg) {
int id = *((int *)arg);
int minha_direcao = id % 2; // A direção é determinada pelo id do carro.
// O carro espera um tempo aleatório antes de tentar atravessar a ponte.
sleep(rand() % MAX_TEMPO_CHEGADA + 1);
pthread_mutex_lock(&mutex); // Adquire o lock antes de manipular os recursos compartilhados.
int inicio_espera = time(NULL); // Registra o tempo de início da espera.
// Tentar a ponte principal.
while (direcao_na_ponte != -1 && (direcao_na_ponte != minha_direcao || carros_na_ponte == MAX_CARROS_PONTE || contador_carros_mesmo_sentido == MAX_CARROS_PONTE)) {
// Se não for possível usar a ponte principal, tentar a ponte antiga.
if (direcao_na_ponte_antiga == -1 || direcao_na_ponte_antiga == minha_direcao && carros_na_ponte_antiga < MAX_CARROS_PONTE_ANTIGA && contador_carros_mesmo_sentido_antiga < MAX_CARROS_PONTE_ANTIGA) {
if (direcao_na_ponte_antiga == -1 || contador_carros_mesmo_sentido_antiga == MAX_CARROS_PONTE_ANTIGA) {
direcao_na_ponte_antiga = minha_direcao;
contador_carros_mesmo_sentido_antiga = 0;
if (ponte_antiga_ocupada == -1) {
ponte_antiga_ocupada = time(NULL); // Registra o tempo em que a ponte antiga começou a ser ocupada.
}
}
// Atualiza o estado da ponte antiga.
carros_na_ponte_antiga++;
contador_carros_mesmo_sentido_antiga++;
carros_por_direcao[minha_direcao]++;
printf("Carro %d está atravessando na direção %d na ponte antiga\n", id, minha_direcao); // Imprime que o carro começou a atravessar a ponte antiga.
sleep(TEMPO_ESPACO_ANTIGA); // Adicionado espaço entre carros na ponte antiga.
pthread_mutex_unlock(&mutex); // Libera o lock após manipular os recursos compartilhados.
// Simula o tempo que o carro leva para atravessar a ponte antiga.
sleep(TEMPO_TRAVESSIA_CARRO_ANTIGA);
pthread_mutex_lock(&mutex); // Adquire o lock novamente para atualizar o estado da ponte.
// Imprime que o carro terminou de atravessar a ponte antiga.
printf("Carro %d terminou de atravessar na direção %d na ponte antiga\n", id, minha_direcao);
carros_na_ponte_antiga--; // Decrementa o número de carros na ponte antiga.
// Caso a ponte antiga esteja vazia, notifica os carros.
if (carros_na_ponte_antiga == 0) {
direcao_na_ponte_antiga = -1;
tempo_total_ocupado_antiga += time(NULL) - ponte_antiga_ocupada;
ponte_antiga_ocupada = -1;
pthread_cond_broadcast(&cond_carro_antiga[!minha_direcao]);
pthread_cond_broadcast(&cond_carro[!minha_direcao]);
} else {
pthread_cond_signal(&cond_carro_antiga[minha_direcao]);
pthread_cond_signal(&cond_carro[minha_direcao]);
}
// Libera o lock e a memória alocada para o carro que atravessou na ponte antiga.
pthread_mutex_unlock(&mutex);
free(arg);
return NULL;
} else {
pthread_cond_wait(&cond_carro[minha_direcao], &mutex); // Caso não consiga passar na antiga, aguarda na principal.
}
}
int fim_espera = time(NULL); // Registra o tempo de fim da espera.
int tempo_espera = fim_espera - inicio_espera; // Calcula o tempo total de espera.
// Atualiza as estatísticas de tempo de espera.
tempo_min_espera_carros = tempo_espera < tempo_min_espera_carros ? tempo_espera : tempo_min_espera_carros;
tempo_max_espera_carros = tempo_espera > tempo_max_espera_carros ? tempo_espera : tempo_max_espera_carros;
tempo_total_espera_carros += tempo_espera;
// Se 5 carros já passaram e a ponte estiver vazia, define a direção do tráfego.
if (direcao_na_ponte == -1 || contador_carros_mesmo_sentido == MAX_CARROS_PONTE) {
direcao_na_ponte = minha_direcao;
contador_carros_mesmo_sentido = 0;
if (ponte_ocupada == -1) {
ponte_ocupada = time(NULL); // Registra o tempo em que a ponte começou a ser ocupada.
}
}
// Atualiza o estado da ponte.
carros_na_ponte++;
contador_carros_mesmo_sentido++;
carros_por_direcao[minha_direcao]++;
printf("Carro %d está atravessando na direção %d na ponte principal\n", id, minha_direcao); // Imprime que o carro começou a atravessar a ponte.
sleep(TEMPO_ESPACO); // Espera um intervalo antes de permitir o próximo carro na ponte principal.
pthread_mutex_unlock(&mutex); // Libera o lock após manipular os recursos compartilhados.
// Simula o tempo que o carro leva para atravessar a ponte principal.
sleep(TEMPO_TRAVESSIA_CARRO);
pthread_mutex_lock(&mutex); // Adquire o lock novamente para atualizar o estado da ponte.
// Imprime que o carro terminou de atravessar a ponte principal.
printf("Carro %d terminou de atravessar na direção %d na ponte principal\n", id, minha_direcao);
carros_na_ponte--; // Decrementa o número de carros na ponte principal.
// Se a ponte estiver vazia, notifica veículos da direção oposta. Caso contrário, notifica veículos da mesma direção.
if (carros_na_ponte == 0 && caminhoes_na_ponte == 0) {
direcao_na_ponte = -1;
tempo_total_ocupado += time(NULL) - ponte_ocupada;
ponte_ocupada = -1;
pthread_cond_broadcast(&cond_carro[!minha_direcao]);
pthread_cond_broadcast(&cond_caminhao[!minha_direcao]);
} else {
pthread_cond_signal(&cond_carro[minha_direcao]);
pthread_cond_signal(&cond_caminhao[minha_direcao]);
}
// Libera o lock e a memória alocada para o id do carro.
pthread_mutex_unlock(&mutex);
free(arg);
return NULL;
}
// Função que será executada por cada thread (caminhão).
void *caminhao(void *arg) {
int id = *((int *)arg);
int minha_direcao = id % 2; // A direção é determinada pelo id do caminhão.
// O caminhão espera um tempo aleatório antes de tentar atravessar a ponte.
sleep(rand() % MAX_TEMPO_CHEGADA + 1);
pthread_mutex_lock(&mutex); // Adquire o lock antes de manipular os recursos compartilhados.
int inicio_espera = time(NULL); // Registra o tempo de início da espera.
// Espera até que a ponte esteja vazia, ou a ponte esteja na mesma direção e haja espaço suficiente na ponte, ou até que 5 carros ou 1 caminhão atravessem.
while (direcao_na_ponte != -1 && (direcao_na_ponte != minha_direcao || carros_na_ponte > 0 || caminhoes_na_ponte == MAX_CAMINHAO_PONTE || contador_caminhoes_mesmo_sentido == MAX_CAMINHAO_PONTE)) {
pthread_cond_wait(&cond_caminhao[minha_direcao], &mutex);
}
int fim_espera = time(NULL); // Registra o tempo de fim da espera.
int tempo_espera = fim_espera - inicio_espera; // Calcula o tempo total de espera.
// Atualiza as estatísticas de tempo de espera.
tempo_min_espera_caminhoes = tempo_espera < tempo_min_espera_caminhoes ? tempo_espera : tempo_min_espera_caminhoes;
tempo_max_espera_caminhoes = tempo_espera > tempo_max_espera_caminhoes ? tempo_espera : tempo_max_espera_caminhoes;
tempo_total_espera_caminhoes += tempo_espera;
//Se 1 caminhão passou e a ponte estiver vazia, define a direção do tráfego.
if (direcao_na_ponte == -1 || contador_caminhoes_mesmo_sentido == MAX_CAMINHAO_PONTE) {
direcao_na_ponte = minha_direcao;
contador_caminhoes_mesmo_sentido = 0;
if (ponte_ocupada == -1) {
ponte_ocupada = time(NULL); // Registra o tempo em que a ponte começou a ser ocupada.
}
}
// Atualiza o estado da ponte.
caminhoes_na_ponte++;
contador_caminhoes_mesmo_sentido++;
caminhoes_por_direcao[minha_direcao]++;
printf("Caminhao %d está atravessando na direção %d\n", id, minha_direcao); // Imprime que o caminhão começou a atravessar a ponte.
sleep(TEMPO_ESPACO); // Espera um intervalo antes de permitir o próximo caminhão.
pthread_mutex_unlock(&mutex); // Libera o lock após manipular os recursos compartilhados.
// Simula o tempo que o caminhão leva para atravessar a ponte.
sleep(TEMPO_TRAVESSIA_CAMINHAO);
pthread_mutex_lock(&mutex); // Adquire o lock novamente para atualizar o estado da ponte.
// Imprime que o caminhão terminou de atravessar a ponte.
printf("Caminhao %d terminou de atravessar na direção %d\n", id, minha_direcao);
caminhoes_na_ponte--; // Decrementa o número de caminhões na ponte.
// Se a ponte estiver vazia, notifica veículos da direção oposta. Caso contrário, notifica veículos da mesma direção.
if (carros_na_ponte == 0 && caminhoes_na_ponte == 0) {
direcao_na_ponte = -1;
tempo_total_ocupado += time(NULL) - ponte_ocupada; // Atualiza o tempo total que a ponte principal foi ocupada.
ponte_ocupada = -1;
pthread_cond_broadcast(&cond_carro[!minha_direcao]);
pthread_cond_broadcast(&cond_caminhao[!minha_direcao]);
} else {
pthread_cond_signal(&cond_caminhao[minha_direcao]);
pthread_cond_signal(&cond_carro[minha_direcao]);
}
// Libera o lock e a memória alocada para o id do caminhão.
pthread_mutex_unlock(&mutex);
free(arg);
return NULL;
}
// Função principal que inicializa e gerencia a simulação.
int main() {
SetConsoleOutputCP(CP_UTF8); // Define o conjunto de caracteres de saída do console para UTF-8.
pthread_t threads_carros[NUM_CARROS]; // Declara um array de threads para cada carro.
pthread_t threads_caminhoes[NUM_CAMINHOES]; // Declara um array de threads para cada caminhão.
int inicio_execucao = time(NULL); // Registra o tempo de início da execução.
// Cria as threads de carros.
for (int i = 0; i < NUM_CARROS; i++) {
int *id = malloc(sizeof(int));
*id = i;
pthread_create(&threads_carros[i], NULL, carro, id);
}
// Cria as threads de caminhões.
for (int i = 0; i < NUM_CAMINHOES; i++) {
int *id = malloc(sizeof(int));
*id = i;
pthread_create(&threads_caminhoes[i], NULL, caminhao, id);
}
// Espera todas as threads dos veículos terminarem.
for (int i = 0; i < NUM_CARROS; i++) {
pthread_join(threads_carros[i], NULL);
}
for (int i = 0; i < NUM_CAMINHOES; i++) {
pthread_join(threads_caminhoes[i], NULL);
}
int fim_execucao = time(NULL); // Registra o tempo de fim da execução.
// Calcula o tempo total de execução.
tempo_total_execucao = fim_execucao - inicio_execucao;
// Imprime as estatísticas coletadas.
printf("\n----------------------------------------------------------------");
printf("\n| Estatísticas |\n");
printf("| |");
printf("\n| 🚗 Quantidade de Carros que cruzaram cada sentido: %d, %d |\n", carros_por_direcao[0], carros_por_direcao[1]);
printf("| 🚗 Tempo mínimo de espera para Carros: %d s |\n", tempo_min_espera_carros);
printf("| 🚗 Tempo máximo de espera para Carros: %d s |\n", tempo_max_espera_carros);
printf("| 🚗 Tempo médio de espera para Carros: %0.2f s |\n", tempo_total_espera_carros / NUM_CARROS);
printf("| |");
printf("\n| 🚚 Quantidade de Caminhões que cruzaram cada sentido: %d, %d |\n", caminhoes_por_direcao[0], caminhoes_por_direcao[1]);
printf("| 🚚 Tempo mínimo de espera para Caminhões: %02d s |\n", tempo_min_espera_caminhoes);
printf("| 🚚 Tempo máximo de espera para Caminhões: %d s |\n", tempo_max_espera_caminhoes);
printf("| 🚚 Tempo médio de espera para Caminhões: %0.2f s |\n", tempo_total_espera_caminhoes / NUM_CAMINHOES);
printf("| |");
printf("\n| ⌚ Eficiência da ponte: %0.2f%% |\n", ((double)tempo_total_ocupado / tempo_total_execucao) * 100);
printf("| ⌛ Eficiência da ponte antiga: %0.2f%% |\n", ((double)tempo_total_ocupado_antiga / tempo_total_execucao) * 100);
printf("| |\n");
printf("----------------------------------------------------------------\n");
return 0;
}