taskc/relay_race/{given → src}/relay_race.c RENAMED
@@ -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 team_number = private_data->thread_number
158
- - shared_data->team_count;
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
  }