pthreads/{position_race/position_race.c → relay_race/relay_race.c} RENAMED
@@ -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 thread_count;
 
 
 
 
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
- shared_thread_data->thread_count = thread_count;
 
41
  shared_thread_data->position = 0;
42
- error = pthread_mutex_init(&shared_thread_data->position_mutex, NULL);
43
- error = pthread_mutex_init(&shared_thread_data->stdout_mutex, /*attr*/NULL);
 
 
 
 
 
 
 
 
 
 
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(shared_thread_data->thread_count * sizeof(pthread_t));
75
 
76
  private_thread_data_t* private_thread_data = (private_thread_data_t*)
77
- calloc(shared_thread_data->thread_count, sizeof(private_thread_data_t));
78
 
79
  if (threads && private_thread_data) {
80
- for (size_t index = 0; index < shared_thread_data->thread_count; ++index) {
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, run
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 < shared_thread_data->thread_count; ++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->thread_count);
106
  error = 22;
107
  }
108
 
109
  return error;
110
  }
111
 
112
- void* run(void* data) {
 
 
 
 
 
 
 
 
 
 
 
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
- const size_t my_position = ++shared_data->position;
 
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("Thread %zu/%zu: I arrived at position %zu\n"
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
  }