@@ -1,167 +1,197 @@
|
|
1 |
// Copyright 2021 Jeisson Hidalgo <jeisson.hidalgo@ucr.ac.cr> CC-BY 4.0
|
2 |
|
3 |
#define _DEFAULT_SOURCE
|
4 |
|
5 |
#include <assert.h>
|
6 |
#include <inttypes.h>
|
7 |
#include <pthread.h>
|
8 |
#include <semaphore.h>
|
9 |
#include <stdint.h>
|
10 |
#include <stdio.h>
|
11 |
#include <stdlib.h>
|
12 |
#include <unistd.h>
|
13 |
|
14 |
typedef struct shared_data {
|
15 |
size_t team_count;
|
16 |
useconds_t stage1_duration;
|
17 |
useconds_t stage2_duration;
|
18 |
size_t position;
|
|
|
|
|
|
|
19 |
} shared_data_t;
|
20 |
|
21 |
typedef struct private_data {
|
22 |
size_t thread_number; // rank
|
23 |
shared_data_t* shared_data;
|
24 |
} private_data_t;
|
25 |
|
26 |
int create_threads(shared_data_t* shared_data);
|
27 |
int analyze_arguments(int argc, char* argv[], shared_data_t* shared_data);
|
28 |
void* start_race(void* data);
|
29 |
void* finish_race(void* data);
|
30 |
|
31 |
int main(int argc, char* argv[]) {
|
32 |
int error = EXIT_SUCCESS;
|
33 |
|
34 |
shared_data_t* shared_data = (shared_data_t*)
|
35 |
calloc(1, sizeof(shared_data_t));
|
36 |
|
37 |
if (shared_data) {
|
38 |
error = analyze_arguments(argc, argv, shared_data);
|
39 |
if (error == EXIT_SUCCESS) {
|
40 |
shared_data->position = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
-
if (error == EXIT_SUCCESS) {
|
43 |
struct timespec start_time, finish_time;
|
44 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
|
45 |
|
46 |
error = create_threads(shared_data);
|
47 |
|
48 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
|
49 |
double elapsed_time = finish_time.tv_sec - start_time.tv_sec +
|
50 |
(finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
|
51 |
printf("execution time: %.9lfs\n", elapsed_time);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
} else {
|
53 |
fprintf(stderr, "error: could not init mutex\n");
|
54 |
error = 11;
|
55 |
}
|
56 |
}
|
57 |
|
58 |
free(shared_data);
|
59 |
} else {
|
60 |
fprintf(stderr, "error: could not allocated shared memory\n");
|
61 |
error = 12;
|
62 |
}
|
63 |
|
64 |
return error;
|
65 |
}
|
66 |
|
67 |
int analyze_arguments(int argc, char* argv[]
|
68 |
, shared_data_t* shared_data) {
|
69 |
if (argc == 4) {
|
70 |
if ( sscanf(argv[1], "%zu", &shared_data->team_count) != 1
|
71 |
|| shared_data->team_count == 0 ) {
|
72 |
fprintf(stderr, "invalid team count: %s\n", argv[1]);
|
73 |
return 11;
|
74 |
}
|
75 |
|
76 |
if ( sscanf(argv[2], "%u", &shared_data->stage1_duration) != 1 ) {
|
77 |
fprintf(stderr, "invalid stage 1 duration: %s\n", argv[2]);
|
78 |
return 12;
|
79 |
}
|
80 |
|
81 |
if ( sscanf(argv[3], "%u", &shared_data->stage2_duration) != 1 ) {
|
82 |
fprintf(stderr, "invalid stage 2 duration: %s\n", argv[3]);
|
83 |
return 13;
|
84 |
}
|
85 |
return EXIT_SUCCESS;
|
86 |
} else {
|
87 |
fprintf(stderr, "usage: relay_race teams stage1duration stage2duration\n");
|
88 |
return 10;
|
89 |
}
|
90 |
}
|
91 |
|
92 |
int create_threads(shared_data_t* shared_data) {
|
93 |
int error = EXIT_SUCCESS;
|
94 |
|
95 |
const size_t thread_count = 2 * shared_data->team_count;
|
96 |
pthread_t* threads = (pthread_t*) malloc(thread_count * sizeof(pthread_t));
|
97 |
|
98 |
private_data_t* private_data = (private_data_t*)
|
99 |
calloc(thread_count, sizeof(private_data_t));
|
100 |
|
101 |
if (threads && private_data) {
|
102 |
for (size_t index = 0; index < shared_data->team_count; ++index) {
|
103 |
private_data[index].thread_number = index;
|
104 |
private_data[index].shared_data = shared_data;
|
105 |
|
106 |
error = pthread_create(&threads[index], NULL, start_race
|
107 |
, &private_data[index]);
|
108 |
|
109 |
if (error) {
|
110 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
111 |
error = 21;
|
112 |
}
|
113 |
}
|
114 |
|
115 |
for (size_t index = shared_data->team_count; index < thread_count;
|
116 |
++index) {
|
117 |
private_data[index].thread_number = index;
|
118 |
private_data[index].shared_data = shared_data;
|
119 |
|
120 |
error = pthread_create(&threads[index], NULL, finish_race
|
121 |
, &private_data[index]);
|
122 |
|
123 |
if (error) {
|
124 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
125 |
error = 21;
|
126 |
}
|
127 |
}
|
128 |
|
129 |
for (size_t index = 0; index < thread_count; ++index) {
|
130 |
pthread_join(threads[index], NULL);
|
131 |
}
|
132 |
|
133 |
free(private_data);
|
134 |
free(threads);
|
135 |
} else {
|
136 |
fprintf(stderr, "error: could not allocate memory for %zu threads\n"
|
137 |
, shared_data->team_count);
|
138 |
error = 22;
|
139 |
}
|
140 |
|
141 |
return error;
|
142 |
}
|
143 |
|
144 |
void* start_race(void* data) {
|
145 |
private_data_t* private_data = (private_data_t*)data;
|
146 |
shared_data_t* shared_data = private_data->shared_data;
|
147 |
|
|
|
|
|
|
|
|
|
148 |
usleep(1000 * shared_data->stage1_duration);
|
|
|
149 |
|
150 |
return NULL;
|
151 |
}
|
152 |
|
153 |
void* finish_race(void* data) {
|
154 |
private_data_t* private_data = (private_data_t*)data;
|
155 |
shared_data_t* shared_data = private_data->shared_data;
|
156 |
|
157 |
-
const size_t
|
158 |
-
|
159 |
assert(team_number < shared_data->team_count);
|
160 |
|
|
|
|
|
161 |
usleep(1000 * shared_data->stage2_duration);
|
162 |
|
|
|
163 |
const size_t our_position = ++shared_data->position;
|
|
|
164 |
printf("Place %zu: team %zu\n", our_position, team_number);
|
|
|
|
|
165 |
|
166 |
return NULL;
|
167 |
}
|
1 |
// Copyright 2021 Jeisson Hidalgo <jeisson.hidalgo@ucr.ac.cr> CC-BY 4.0
|
2 |
|
3 |
#define _DEFAULT_SOURCE
|
4 |
|
5 |
#include <assert.h>
|
6 |
#include <inttypes.h>
|
7 |
#include <pthread.h>
|
8 |
#include <semaphore.h>
|
9 |
#include <stdint.h>
|
10 |
#include <stdio.h>
|
11 |
#include <stdlib.h>
|
12 |
#include <unistd.h>
|
13 |
|
14 |
typedef struct shared_data {
|
15 |
size_t team_count;
|
16 |
useconds_t stage1_duration;
|
17 |
useconds_t stage2_duration;
|
18 |
size_t position;
|
19 |
+
pthread_barrier_t start_barrier;
|
20 |
+
sem_t* batons;
|
21 |
+
pthread_mutex_t finish_mutex;
|
22 |
} shared_data_t;
|
23 |
|
24 |
typedef struct private_data {
|
25 |
size_t thread_number; // rank
|
26 |
shared_data_t* shared_data;
|
27 |
} private_data_t;
|
28 |
|
29 |
int create_threads(shared_data_t* shared_data);
|
30 |
int analyze_arguments(int argc, char* argv[], shared_data_t* shared_data);
|
31 |
void* start_race(void* data);
|
32 |
void* finish_race(void* data);
|
33 |
|
34 |
int main(int argc, char* argv[]) {
|
35 |
int error = EXIT_SUCCESS;
|
36 |
|
37 |
shared_data_t* shared_data = (shared_data_t*)
|
38 |
calloc(1, sizeof(shared_data_t));
|
39 |
|
40 |
if (shared_data) {
|
41 |
error = analyze_arguments(argc, argv, shared_data);
|
42 |
if (error == EXIT_SUCCESS) {
|
43 |
shared_data->position = 0;
|
44 |
+
error = pthread_barrier_init(&shared_data->start_barrier,
|
45 |
+
/*attr*/ NULL, /*count*/ shared_data->team_count);
|
46 |
+
shared_data->batons = (sem_t*) calloc(shared_data->team_count
|
47 |
+
, sizeof(sem_t));
|
48 |
+
error += pthread_mutex_init(&shared_data->finish_mutex, /*attr*/ NULL);
|
49 |
+
|
50 |
+
if (error == EXIT_SUCCESS && shared_data->batons) {
|
51 |
+
for (size_t index = 0; index < shared_data->team_count; ++index) {
|
52 |
+
sem_init(&shared_data->batons[index], /*pshared*/ 0, /*value*/ 0);
|
53 |
+
}
|
54 |
|
|
|
55 |
struct timespec start_time, finish_time;
|
56 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
|
57 |
|
58 |
error = create_threads(shared_data);
|
59 |
|
60 |
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
|
61 |
double elapsed_time = finish_time.tv_sec - start_time.tv_sec +
|
62 |
(finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
|
63 |
printf("execution time: %.9lfs\n", elapsed_time);
|
64 |
+
|
65 |
+
for (size_t index = 0; index < shared_data->team_count; ++index) {
|
66 |
+
sem_destroy(&shared_data->batons[index]);
|
67 |
+
}
|
68 |
+
pthread_mutex_destroy(&shared_data->finish_mutex);
|
69 |
+
free(shared_data->batons);
|
70 |
+
pthread_barrier_destroy(&shared_data->start_barrier);
|
71 |
} else {
|
72 |
fprintf(stderr, "error: could not init mutex\n");
|
73 |
error = 11;
|
74 |
}
|
75 |
}
|
76 |
|
77 |
free(shared_data);
|
78 |
} else {
|
79 |
fprintf(stderr, "error: could not allocated shared memory\n");
|
80 |
error = 12;
|
81 |
}
|
82 |
|
83 |
return error;
|
84 |
}
|
85 |
|
86 |
int analyze_arguments(int argc, char* argv[]
|
87 |
, shared_data_t* shared_data) {
|
88 |
if (argc == 4) {
|
89 |
if ( sscanf(argv[1], "%zu", &shared_data->team_count) != 1
|
90 |
|| shared_data->team_count == 0 ) {
|
91 |
fprintf(stderr, "invalid team count: %s\n", argv[1]);
|
92 |
return 11;
|
93 |
}
|
94 |
|
95 |
if ( sscanf(argv[2], "%u", &shared_data->stage1_duration) != 1 ) {
|
96 |
fprintf(stderr, "invalid stage 1 duration: %s\n", argv[2]);
|
97 |
return 12;
|
98 |
}
|
99 |
|
100 |
if ( sscanf(argv[3], "%u", &shared_data->stage2_duration) != 1 ) {
|
101 |
fprintf(stderr, "invalid stage 2 duration: %s\n", argv[3]);
|
102 |
return 13;
|
103 |
}
|
104 |
return EXIT_SUCCESS;
|
105 |
} else {
|
106 |
fprintf(stderr, "usage: relay_race teams stage1duration stage2duration\n");
|
107 |
return 10;
|
108 |
}
|
109 |
}
|
110 |
|
111 |
int create_threads(shared_data_t* shared_data) {
|
112 |
int error = EXIT_SUCCESS;
|
113 |
|
114 |
const size_t thread_count = 2 * shared_data->team_count;
|
115 |
pthread_t* threads = (pthread_t*) malloc(thread_count * sizeof(pthread_t));
|
116 |
|
117 |
private_data_t* private_data = (private_data_t*)
|
118 |
calloc(thread_count, sizeof(private_data_t));
|
119 |
|
120 |
if (threads && private_data) {
|
121 |
for (size_t index = 0; index < shared_data->team_count; ++index) {
|
122 |
private_data[index].thread_number = index;
|
123 |
private_data[index].shared_data = shared_data;
|
124 |
|
125 |
error = pthread_create(&threads[index], NULL, start_race
|
126 |
, &private_data[index]);
|
127 |
|
128 |
if (error) {
|
129 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
130 |
error = 21;
|
131 |
}
|
132 |
}
|
133 |
|
134 |
for (size_t index = shared_data->team_count; index < thread_count;
|
135 |
++index) {
|
136 |
private_data[index].thread_number = index;
|
137 |
private_data[index].shared_data = shared_data;
|
138 |
|
139 |
error = pthread_create(&threads[index], NULL, finish_race
|
140 |
, &private_data[index]);
|
141 |
|
142 |
if (error) {
|
143 |
fprintf(stderr, "error: could not create thread %zu\n", index);
|
144 |
error = 21;
|
145 |
}
|
146 |
}
|
147 |
|
148 |
for (size_t index = 0; index < thread_count; ++index) {
|
149 |
pthread_join(threads[index], NULL);
|
150 |
}
|
151 |
|
152 |
free(private_data);
|
153 |
free(threads);
|
154 |
} else {
|
155 |
fprintf(stderr, "error: could not allocate memory for %zu threads\n"
|
156 |
, shared_data->team_count);
|
157 |
error = 22;
|
158 |
}
|
159 |
|
160 |
return error;
|
161 |
}
|
162 |
|
163 |
void* start_race(void* data) {
|
164 |
private_data_t* private_data = (private_data_t*)data;
|
165 |
shared_data_t* shared_data = private_data->shared_data;
|
166 |
|
167 |
+
const size_t rank = private_data->thread_number;
|
168 |
+
const size_t team_number = rank;
|
169 |
+
|
170 |
+
pthread_barrier_wait(&shared_data->start_barrier);
|
171 |
usleep(1000 * shared_data->stage1_duration);
|
172 |
+
sem_post(&shared_data->batons[team_number]);
|
173 |
|
174 |
return NULL;
|
175 |
}
|
176 |
|
177 |
void* finish_race(void* data) {
|
178 |
private_data_t* private_data = (private_data_t*)data;
|
179 |
shared_data_t* shared_data = private_data->shared_data;
|
180 |
|
181 |
+
const size_t rank = private_data->thread_number;
|
182 |
+
const size_t team_number = rank - shared_data->team_count;
|
183 |
assert(team_number < shared_data->team_count);
|
184 |
|
185 |
+
// wait(batons[team_number])
|
186 |
+
sem_wait(&shared_data->batons[team_number]);
|
187 |
usleep(1000 * shared_data->stage2_duration);
|
188 |
|
189 |
+
pthread_mutex_lock(&shared_data->finish_mutex);
|
190 |
const size_t our_position = ++shared_data->position;
|
191 |
+
// if (our_position <= 3) {
|
192 |
printf("Place %zu: team %zu\n", our_position, team_number);
|
193 |
+
// }
|
194 |
+
pthread_mutex_unlock(&shared_data->finish_mutex);
|
195 |
|
196 |
return NULL;
|
197 |
}
|