@@ -1,145 +1,151 @@
|
|
1 |
// Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
|
2 |
|
3 |
#include <assert.h>
|
4 |
#include <errno.h>
|
5 |
#include <pthread.h>
|
6 |
#include <stdlib.h>
|
7 |
#include <sys/random.h>
|
8 |
#include <stdio.h>
|
9 |
|
10 |
#include "common.h"
|
11 |
#include "consumer.h"
|
12 |
#include "producer.h"
|
13 |
#include "simulation.h"
|
14 |
|
15 |
int analyze_arguments(simulation_t* simulation, int argc, char* argv[]);
|
16 |
int create_consumers_producers(simulation_t* simulation);
|
17 |
int join_threads(size_t count, pthread_t* threads);
|
18 |
|
19 |
simulation_t* simulation_create() {
|
20 |
simulation_t* simulation = (simulation_t*) calloc(1, sizeof(simulation_t));
|
21 |
if (simulation) {
|
22 |
simulation->unit_count = 0;
|
23 |
simulation->producer_count = 0;
|
24 |
simulation->consumer_count = 0;
|
25 |
simulation->producer_min_delay = 0;
|
26 |
simulation->producer_max_delay = 0;
|
27 |
simulation->consumer_min_delay = 0;
|
28 |
simulation->consumer_max_delay = 0;
|
29 |
queue_init(&simulation->queue);
|
|
|
30 |
simulation->next_unit = 0;
|
|
|
|
|
31 |
simulation->consumed_count = 0;
|
32 |
}
|
33 |
return simulation;
|
34 |
}
|
35 |
|
36 |
void simulation_destroy(simulation_t* simulation) {
|
37 |
assert(simulation);
|
|
|
|
|
|
|
38 |
queue_destroy(&simulation->queue);
|
39 |
free(simulation);
|
40 |
}
|
41 |
|
42 |
int simulation_run(simulation_t* simulation, int argc, char* argv[]) {
|
43 |
int error = analyze_arguments(simulation, argc, argv);
|
44 |
if (error == EXIT_SUCCESS) {
|
45 |
unsigned int seed = 0;
|
46 |
getrandom(&seed, sizeof(seed), GRND_NONBLOCK);
|
47 |
srandom(seed);
|
48 |
|
49 |
struct timespec start_time;
|
50 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
|
51 |
|
52 |
error = create_consumers_producers(simulation);
|
53 |
|
54 |
struct timespec finish_time;
|
55 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
|
56 |
|
57 |
double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
|
58 |
(finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
|
59 |
printf("execution time: %.9lfs\n", elapsed);
|
60 |
}
|
61 |
return error;
|
62 |
}
|
63 |
|
64 |
int analyze_arguments(simulation_t* simulation, int argc, char* argv[]) {
|
65 |
int error = EXIT_SUCCESS;
|
66 |
if (argc == 8) {
|
67 |
if (sscanf(argv[1], "%zu", &simulation->unit_count) != 1
|
68 |
|| simulation->unit_count == 0) {
|
69 |
fprintf(stderr, "error: invalid unit count\n");
|
70 |
error = ERR_UNIT_COUNT;
|
71 |
} else if (sscanf(argv[2], "%zu", &simulation->producer_count) != 1
|
72 |
|| simulation->producer_count == 0) {
|
73 |
fprintf(stderr, "error: invalid producer count\n");
|
74 |
error = ERR_PRODUCER_COUNT;
|
75 |
} else if (sscanf(argv[3], "%zu", &simulation->consumer_count) != 1
|
76 |
|| simulation->consumer_count == 0) {
|
77 |
fprintf(stderr, "error: invalid consumer count\n");
|
78 |
error = ERR_CONSUMER_COUNT;
|
79 |
} else if (sscanf(argv[4], "%u", &simulation->producer_min_delay) != 1) {
|
80 |
fprintf(stderr, "error: invalid min producer delay\n");
|
81 |
error = ERR_MIN_PROD_DELAY;
|
82 |
} else if (sscanf(argv[5], "%u", &simulation->producer_max_delay) != 1) {
|
83 |
fprintf(stderr, "error: invalid max producer delay\n");
|
84 |
error = ERR_MAX_PROD_DELAY;
|
85 |
} else if (sscanf(argv[6], "%u", &simulation->consumer_min_delay) != 1) {
|
86 |
fprintf(stderr, "error: invalid min consumer delay\n");
|
87 |
error = ERR_MIN_CONS_DELAY;
|
88 |
} else if (sscanf(argv[7], "%u", &simulation->consumer_max_delay) != 1) {
|
89 |
fprintf(stderr, "error: invalid max consumer delay\n");
|
90 |
error = ERR_MAX_CONS_DELAY;
|
91 |
}
|
92 |
} else {
|
93 |
fprintf(stderr, "usage: producer_consumer buffer_capacity rounds"
|
94 |
" producer_min_delay producer_max_delay"
|
95 |
" consumer_min_delay consumer_max_delay\n");
|
96 |
error = ERR_NO_ARGS;
|
97 |
}
|
98 |
return error;
|
99 |
}
|
100 |
|
101 |
pthread_t* create_threads(size_t count, void*(*subroutine)(void*), void* data) {
|
102 |
pthread_t* threads = (pthread_t*) calloc(count, sizeof(pthread_t));
|
103 |
if (threads) {
|
104 |
for (size_t index = 0; index < count; ++index) {
|
105 |
if (pthread_create(&threads[index], /*attr*/ NULL, subroutine, data)
|
106 |
== EXIT_SUCCESS) {
|
107 |
} else {
|
108 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
109 |
join_threads(index, threads);
|
110 |
return NULL;
|
111 |
}
|
112 |
}
|
113 |
}
|
114 |
return threads;
|
115 |
}
|
116 |
|
117 |
int join_threads(size_t count, pthread_t* threads) {
|
118 |
int error = EXIT_SUCCESS;
|
119 |
for (size_t index = 0; index < count; ++index) {
|
120 |
// todo: sum could not be right
|
121 |
error += pthread_join(threads[index], /*value_ptr*/ NULL);
|
122 |
}
|
123 |
free(threads);
|
124 |
return error;
|
125 |
}
|
126 |
|
127 |
int create_consumers_producers(simulation_t* simulation) {
|
128 |
assert(simulation);
|
129 |
int error = EXIT_SUCCESS;
|
130 |
|
131 |
pthread_t* producers = create_threads(simulation->producer_count, produce
|
132 |
, simulation);
|
133 |
pthread_t* consumers = create_threads(simulation->consumer_count, consume
|
134 |
, simulation);
|
135 |
|
136 |
if (producers && consumers) {
|
137 |
join_threads(simulation->producer_count, producers);
|
138 |
join_threads(simulation->consumer_count, consumers);
|
139 |
} else {
|
140 |
fprintf(stderr, "error: could not create threads\n");
|
141 |
error = ERR_CREATE_THREAD;
|
142 |
}
|
143 |
|
144 |
return error;
|
145 |
}
|
1 |
// Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
|
2 |
|
3 |
#include <assert.h>
|
4 |
#include <errno.h>
|
5 |
#include <pthread.h>
|
6 |
#include <stdlib.h>
|
7 |
#include <sys/random.h>
|
8 |
#include <stdio.h>
|
9 |
|
10 |
#include "common.h"
|
11 |
#include "consumer.h"
|
12 |
#include "producer.h"
|
13 |
#include "simulation.h"
|
14 |
|
15 |
int analyze_arguments(simulation_t* simulation, int argc, char* argv[]);
|
16 |
int create_consumers_producers(simulation_t* simulation);
|
17 |
int join_threads(size_t count, pthread_t* threads);
|
18 |
|
19 |
simulation_t* simulation_create() {
|
20 |
simulation_t* simulation = (simulation_t*) calloc(1, sizeof(simulation_t));
|
21 |
if (simulation) {
|
22 |
simulation->unit_count = 0;
|
23 |
simulation->producer_count = 0;
|
24 |
simulation->consumer_count = 0;
|
25 |
simulation->producer_min_delay = 0;
|
26 |
simulation->producer_max_delay = 0;
|
27 |
simulation->consumer_min_delay = 0;
|
28 |
simulation->consumer_max_delay = 0;
|
29 |
queue_init(&simulation->queue);
|
30 |
+
pthread_mutex_init(&simulation->can_access_next_unit, /* attr */ NULL);
|
31 |
simulation->next_unit = 0;
|
32 |
+
sem_init(&simulation->can_consume, /* pshared */ 0, /* value */ 0);
|
33 |
+
pthread_mutex_init(&simulation->can_access_consumed_count, /* attr */ NULL);
|
34 |
simulation->consumed_count = 0;
|
35 |
}
|
36 |
return simulation;
|
37 |
}
|
38 |
|
39 |
void simulation_destroy(simulation_t* simulation) {
|
40 |
assert(simulation);
|
41 |
+
pthread_mutex_destroy(&simulation->can_access_consumed_count);
|
42 |
+
sem_destroy(&simulation->can_consume);
|
43 |
+
pthread_mutex_destroy(&simulation->can_access_next_unit);
|
44 |
queue_destroy(&simulation->queue);
|
45 |
free(simulation);
|
46 |
}
|
47 |
|
48 |
int simulation_run(simulation_t* simulation, int argc, char* argv[]) {
|
49 |
int error = analyze_arguments(simulation, argc, argv);
|
50 |
if (error == EXIT_SUCCESS) {
|
51 |
unsigned int seed = 0;
|
52 |
getrandom(&seed, sizeof(seed), GRND_NONBLOCK);
|
53 |
srandom(seed);
|
54 |
|
55 |
struct timespec start_time;
|
56 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
|
57 |
|
58 |
error = create_consumers_producers(simulation);
|
59 |
|
60 |
struct timespec finish_time;
|
61 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
|
62 |
|
63 |
double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
|
64 |
(finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
|
65 |
printf("execution time: %.9lfs\n", elapsed);
|
66 |
}
|
67 |
return error;
|
68 |
}
|
69 |
|
70 |
int analyze_arguments(simulation_t* simulation, int argc, char* argv[]) {
|
71 |
int error = EXIT_SUCCESS;
|
72 |
if (argc == 8) {
|
73 |
if (sscanf(argv[1], "%zu", &simulation->unit_count) != 1
|
74 |
|| simulation->unit_count == 0) {
|
75 |
fprintf(stderr, "error: invalid unit count\n");
|
76 |
error = ERR_UNIT_COUNT;
|
77 |
} else if (sscanf(argv[2], "%zu", &simulation->producer_count) != 1
|
78 |
|| simulation->producer_count == 0) {
|
79 |
fprintf(stderr, "error: invalid producer count\n");
|
80 |
error = ERR_PRODUCER_COUNT;
|
81 |
} else if (sscanf(argv[3], "%zu", &simulation->consumer_count) != 1
|
82 |
|| simulation->consumer_count == 0) {
|
83 |
fprintf(stderr, "error: invalid consumer count\n");
|
84 |
error = ERR_CONSUMER_COUNT;
|
85 |
} else if (sscanf(argv[4], "%u", &simulation->producer_min_delay) != 1) {
|
86 |
fprintf(stderr, "error: invalid min producer delay\n");
|
87 |
error = ERR_MIN_PROD_DELAY;
|
88 |
} else if (sscanf(argv[5], "%u", &simulation->producer_max_delay) != 1) {
|
89 |
fprintf(stderr, "error: invalid max producer delay\n");
|
90 |
error = ERR_MAX_PROD_DELAY;
|
91 |
} else if (sscanf(argv[6], "%u", &simulation->consumer_min_delay) != 1) {
|
92 |
fprintf(stderr, "error: invalid min consumer delay\n");
|
93 |
error = ERR_MIN_CONS_DELAY;
|
94 |
} else if (sscanf(argv[7], "%u", &simulation->consumer_max_delay) != 1) {
|
95 |
fprintf(stderr, "error: invalid max consumer delay\n");
|
96 |
error = ERR_MAX_CONS_DELAY;
|
97 |
}
|
98 |
} else {
|
99 |
fprintf(stderr, "usage: producer_consumer buffer_capacity rounds"
|
100 |
" producer_min_delay producer_max_delay"
|
101 |
" consumer_min_delay consumer_max_delay\n");
|
102 |
error = ERR_NO_ARGS;
|
103 |
}
|
104 |
return error;
|
105 |
}
|
106 |
|
107 |
pthread_t* create_threads(size_t count, void*(*subroutine)(void*), void* data) {
|
108 |
pthread_t* threads = (pthread_t*) calloc(count, sizeof(pthread_t));
|
109 |
if (threads) {
|
110 |
for (size_t index = 0; index < count; ++index) {
|
111 |
if (pthread_create(&threads[index], /*attr*/ NULL, subroutine, data)
|
112 |
== EXIT_SUCCESS) {
|
113 |
} else {
|
114 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
115 |
join_threads(index, threads);
|
116 |
return NULL;
|
117 |
}
|
118 |
}
|
119 |
}
|
120 |
return threads;
|
121 |
}
|
122 |
|
123 |
int join_threads(size_t count, pthread_t* threads) {
|
124 |
int error = EXIT_SUCCESS;
|
125 |
for (size_t index = 0; index < count; ++index) {
|
126 |
// todo: sum could not be right
|
127 |
error += pthread_join(threads[index], /*value_ptr*/ NULL);
|
128 |
}
|
129 |
free(threads);
|
130 |
return error;
|
131 |
}
|
132 |
|
133 |
int create_consumers_producers(simulation_t* simulation) {
|
134 |
assert(simulation);
|
135 |
int error = EXIT_SUCCESS;
|
136 |
|
137 |
pthread_t* producers = create_threads(simulation->producer_count, produce
|
138 |
, simulation);
|
139 |
pthread_t* consumers = create_threads(simulation->consumer_count, consume
|
140 |
, simulation);
|
141 |
|
142 |
if (producers && consumers) {
|
143 |
join_threads(simulation->producer_count, producers);
|
144 |
join_threads(simulation->consumer_count, consumers);
|
145 |
} else {
|
146 |
fprintf(stderr, "error: could not create threads\n");
|
147 |
error = ERR_CREATE_THREAD;
|
148 |
}
|
149 |
|
150 |
return error;
|
151 |
}
|