-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathproblem_3.c
251 lines (197 loc) · 12.2 KB
/
problem_3.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
#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 100 // 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_ESPACO 1 // Define o intervalo entre os veículos.
#define MAX_CARROS_PONTE 5 // Define o número máximo de carros que podem estar na ponte 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};
// 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; // Variável adicional para rastrear a quantidade de caminhões na ponte.
int direcao_na_ponte = -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;
// 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;
// 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.
// Espera até que a ponte esteja vazia, ou carros estejam indo na mesma direção e haja espaço suficiente na ponte, ou até que 5 carros atravessem.
while (direcao_na_ponte != -1 && (direcao_na_ponte != minha_direcao || carros_na_ponte == MAX_CARROS_PONTE || contador_carros_mesmo_sentido == MAX_CARROS_PONTE)) {
pthread_cond_wait(&cond_carro[minha_direcao], &mutex); // Aguarda a notificação junto com os carros da mesma direção.
}
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++; // Incrementa o contador de carros no mesmo sentido.
carros_por_direcao[minha_direcao]++;
printf("Carro %d está atravessando na direção %d\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.
pthread_mutex_unlock(&mutex); // Libera o lock após manipular os recursos compartilhados.
// Simula o tempo que o carro leva para atravessar a ponte.
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.
printf("Carro %d terminou de atravessar na direção %d\n", id, minha_direcao);
carros_na_ponte--; // Decrementa o número de carros 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;
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.
pthread_mutex_unlock(&mutex);
free(arg); // Libera a memória alocada para o id do carro.
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 foi 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.
pthread_mutex_unlock(&mutex);
free(arg); // Libera a memória alocada para o id do caminhão.
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("| |\n");
printf("----------------------------------------------------------------\n");
return 0;
}