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