2-pthreads/{position_race/position_race.c → relay_race/relay_race.c} RENAMED
@@ -1,95 +1,193 @@
 
1
  #include <pthread.h>
 
2
  #include <stdio.h>
3
  #include <stdlib.h>
4
  #include <time.h>
5
  #include <unistd.h>
6
 
7
- /*
8
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
9
- void* (*start_routine)(void*), void *arg);
10
- */
11
 
12
- // thread shared data
13
  typedef struct
14
  {
15
- size_t thread_count;
 
 
 
 
 
 
16
  size_t position;
17
- pthread_mutex_t mutex;
 
 
 
 
 
 
 
18
  } shared_data_t;
19
 
20
- // thread private data
21
  typedef struct
22
  {
 
 
23
  size_t thread_id;
 
24
  shared_data_t* shared_data;
25
  } private_data_t;
26
 
27
- void* run(void* data)
28
- {
29
- private_data_t* private_data = (private_data_t*)data;
30
- shared_data_t* shared_data = private_data->shared_data;
31
-
32
- pthread_mutex_lock( &shared_data->mutex );
33
- ++shared_data->position;
34
-
35
- printf("thread %zu/%zu I arrived at position %zu\n"
36
- , private_data->thread_id, shared_data->thread_count
37
- , shared_data->position);
38
-
39
- pthread_mutex_unlock( &shared_data->mutex );
40
 
41
- return NULL;
42
- }
 
43
 
44
  int main(int argc, char* argv[])
45
  {
46
- size_t thread_count = sysconf(_SC_NPROCESSORS_ONLN);
47
- if ( argc >= 2 )
48
- {
49
- if ( sscanf(argv[1], "%zu", &thread_count) != 1 || thread_count == 0 )
50
- return (void)fprintf(stderr, "hello_w: error: invalid thread count: %s\n", argv[1]), 1;
51
- }
 
 
 
52
 
 
 
 
 
 
 
 
53
  pthread_t* threads = (pthread_t*)malloc(thread_count * sizeof(pthread_t));
54
  if ( threads == NULL )
55
- return (void)fprintf(stderr, "hello_w: error: could not allocate memory for: %zu threads\n", thread_count), 2;
 
 
 
56
 
 
57
  struct timespec start_time;
58
  clock_gettime(CLOCK_MONOTONIC, &start_time);
59
 
60
- shared_data_t shared_data;
61
- shared_data.thread_count = thread_count;
62
- shared_data.position = 0;
63
- pthread_mutex_init(&shared_data.mutex, NULL);
64
-
65
- private_data_t* private_data = (private_data_t*) calloc(thread_count, sizeof(private_data_t));
66
-
67
- for ( size_t index = 0; index < thread_count; ++index )
68
- {
69
- private_data[index].thread_id = index;
70
- private_data[index].shared_data = &shared_data;
71
- pthread_create(&threads[index], NULL, run, private_data + index);
 
 
 
 
 
 
72
  }
73
 
74
- pthread_mutex_lock( &shared_data.mutex );
75
- printf("Hello from main thread\n");
76
- pthread_mutex_unlock( &shared_data.mutex );
77
-
78
-
79
  for ( size_t index = 0; index < thread_count; ++index )
80
  pthread_join(threads[index], NULL);
81
 
 
82
  struct timespec finish_time;
83
  clock_gettime(CLOCK_MONOTONIC, &finish_time);
84
 
85
- double seconds = finish_time.tv_sec - start_time.tv_sec
 
86
  + (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
 
87
 
88
- printf("Thread creation and join time: %.9lfs\n", seconds);
 
 
89
 
90
- pthread_mutex_destroy(&shared_data.mutex);
 
91
  free(private_data);
92
  free(threads);
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  return 0;
95
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include <assert.h>
2
  #include <pthread.h>
3
+ #include <semaphore.h>
4
  #include <stdio.h>
5
  #include <stdlib.h>
6
  #include <time.h>
7
  #include <unistd.h>
8
 
9
+ #ifdef __APPLE__
10
+ #include "pthread_barrier.h"
11
+ #endif
 
12
 
13
+ // Data shared for al threads
14
  typedef struct
15
  {
16
+ // Number of teams given by user, two threads are created for each team
17
+ size_t team_count;
18
+ // Time in milliseconds that threads wait in stage 1: from start to the partner
19
+ unsigned stage_time_1;
20
+ // Time in milliseconds that threads wait in stage 2: from partner to the finish
21
+ unsigned stage_time_2;
22
+ // Counter located at the finish used to know the position each thread reach
23
  size_t position;
24
+ // A barrier is used at the start of the race to simulate threads departing at the same time
25
+ pthread_barrier_t starting_barrier;
26
+ // An array of semaphores, one for each team, to simulate the batons. Initially, runner 2 of
27
+ // the team will be waiting for the semaphore. When runner 1 reaches runner 2, runner 1 will
28
+ // post to the semaphore
29
+ sem_t* baton_semaphores;
30
+ // A mutex at the finish of the race allows only one runner at time claiming its position
31
+ pthread_mutex_t finish_mutex;
32
  } shared_data_t;
33
 
34
+ // Private thread data: each thread has its own record
35
  typedef struct
36
  {
37
+ // The number of the thread: range [0, team_count[ identifies runners from start to the middle
38
+ // while range [team_count, 2*team_count[ identify runners from middle to the finish
39
  size_t thread_id;
40
+ // Pointer to the shared data record for all threads
41
  shared_data_t* shared_data;
42
  } private_data_t;
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ int analyze_arguments(int argc, char* argv[], shared_data_t* shared_data);
46
+ void* start_race(void* data);
47
+ void* finish_race(void* data);
48
 
49
  int main(int argc, char* argv[])
50
  {
51
+ // Fill the shared data with the values from the arguments
52
+ shared_data_t shared_data;
53
+ int error = analyze_arguments(argc, argv, &shared_data);
54
+ if ( error ) return error;
55
+
56
+ // Init synchronization controls in shared data
57
+ shared_data.position = 0;
58
+ pthread_barrier_init( &shared_data.starting_barrier, NULL, shared_data.team_count );
59
+ pthread_mutex_init( &shared_data.finish_mutex, NULL );
60
 
61
+ // Init the semaphores used as batons, one for each team
62
+ shared_data.baton_semaphores = (sem_t*) calloc( shared_data.team_count, sizeof(sem_t) );
63
+ if ( shared_data.baton_semaphores == NULL )
64
+ return (void)fprintf(stderr, "hello_w: error: could not allocate memory for: %zu semaphores\n", shared_data.team_count), 5;
65
+
66
+ // Create records to control each thread, two per team
67
+ const size_t thread_count = 2 * shared_data.team_count;
68
  pthread_t* threads = (pthread_t*)malloc(thread_count * sizeof(pthread_t));
69
  if ( threads == NULL )
70
+ return (void)fprintf(stderr, "hello_w: error: could not allocate memory for: %zu threads\n", thread_count), 6;
71
+
72
+ // Create a private record, one for each thread (two per team)
73
+ private_data_t* private_data = (private_data_t*) calloc(thread_count, sizeof(private_data_t));
74
 
75
+ // Get a time snapshot to calculate the duration later
76
  struct timespec start_time;
77
  clock_gettime(CLOCK_MONOTONIC, &start_time);
78
 
79
+ // Create the threads, two for each team
80
+ #ifdef INVERTED_TEAM_ORDER
81
+ for ( size_t team = shared_data.team_count - 1; team <= shared_data.team_count - 1; --team )
82
+ #else
83
+ for ( size_t team = 0; team < shared_data.team_count; ++team )
84
+ #endif
85
+ {
86
+ // Create the team's thread that starts the race
87
+ private_data[team].thread_id = team;
88
+ private_data[team].shared_data = &shared_data;
89
+ pthread_create(&threads[team], NULL, start_race, private_data + team);
90
+
91
+ // Create the partner team's thread that finishes the race
92
+ const size_t partner = team + shared_data.team_count;
93
+ assert(partner < thread_count);
94
+ private_data[partner].thread_id = partner;
95
+ private_data[partner].shared_data = &shared_data;
96
+ pthread_create(&threads[partner], NULL, finish_race, private_data + partner);
97
  }
98
 
99
+ // Wait until the race finishes
 
 
 
 
100
  for ( size_t index = 0; index < thread_count; ++index )
101
  pthread_join(threads[index], NULL);
102
 
103
+ // Get the finish time as another time snapshot
104
  struct timespec finish_time;
105
  clock_gettime(CLOCK_MONOTONIC, &finish_time);
106
 
107
+ // Calculate the simulation time
108
+ const double seconds = finish_time.tv_sec - start_time.tv_sec
109
  + (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
110
+ printf("Simulation time: %.9lfs\n", seconds);
111
 
112
+ // Release synchronization mechanisms
113
+ pthread_mutex_destroy(&shared_data.finish_mutex);
114
+ pthread_barrier_destroy( &shared_data.starting_barrier );
115
 
116
+ // Release heap memory
117
+ free(shared_data.baton_semaphores);
118
  free(private_data);
119
  free(threads);
120
 
121
+ return EXIT_SUCCESS;
122
+ }
123
+
124
+ int analyze_arguments(int argc, char* argv[], shared_data_t* shared_data)
125
+ {
126
+ // Three paramets are mandatory
127
+ if ( argc != 4 )
128
+ return (void)fprintf(stderr, "usage: relay_race <teams> <stage_time_1> <stage_time_2>\n"), 1;
129
+
130
+ // Convert text arguments to the shared integer values
131
+ if ( sscanf(argv[1], "%zu", &shared_data->team_count) != 1 || shared_data->team_count == 0 )
132
+ return (void)fprintf(stderr, "hello_w: error: invalid team count: %s\n", argv[1]), 2;
133
+ if ( sscanf(argv[2], "%u", &shared_data->stage_time_1) != 1 )
134
+ return (void)fprintf(stderr, "hello_w: error: invalid stage time 1: %s\n", argv[2]), 3;
135
+ if ( sscanf(argv[3], "%u", &shared_data->stage_time_2) != 1 )
136
+ return (void)fprintf(stderr, "hello_w: error: invalid stage time 2: %s\n", argv[3]), 4;
137
+
138
  return 0;
139
  }
140
+
141
+ // Threads that depart from the start, execute this function. They goal is to give the baton
142
+ // to their partners as fast as they can
143
+ void* start_race(void* data)
144
+ {
145
+ // Get pointers to the private and shared data
146
+ private_data_t* private_data = (private_data_t*)data;
147
+ shared_data_t* shared_data = private_data->shared_data;
148
+
149
+ // Wait at the starting line
150
+ pthread_barrier_wait( &shared_data->starting_barrier );
151
+
152
+ // The race started! Traverse the stage 1. It takes time
153
+ usleep( 1000 * shared_data->stage_time_1 );
154
+
155
+ // I reached my partner, give it the baton
156
+ const size_t team_id = private_data->thread_id;
157
+ sem_post( &shared_data->baton_semaphores[team_id] );
158
+
159
+ // I finished my race
160
+ return NULL;
161
+ }
162
+
163
+ void* finish_race(void* data)
164
+ {
165
+ // Get pointers to the private and shared data
166
+ private_data_t* private_data = (private_data_t*)data;
167
+ shared_data_t* shared_data = private_data->shared_data;
168
+
169
+ // I wait until my partner gives me the baton
170
+ size_t team_id = private_data->thread_id - shared_data->team_count;
171
+ assert(team_id < shared_data->team_count);
172
+ sem_wait( &shared_data->baton_semaphores[team_id] );
173
+
174
+ // My partner gave me the beaton! Traverse the stage 2. It takes time
175
+ usleep( 1000 * shared_data->stage_time_2 );
176
+
177
+ // I arrived to the finish line! grab my position
178
+ pthread_mutex_lock( &shared_data->finish_mutex );
179
+ ++shared_data->position;
180
+
181
+ // Only first runners win the race
182
+ // if ( shared_data->position <= 3 )
183
+ {
184
+ // Report the place that my team reached
185
+ printf( "Place %zu: team %zu\n", shared_data->position, team_id + 1 );
186
+ }
187
+
188
+ // Leave the finish to allow other teams to traverse it
189
+ pthread_mutex_unlock( &shared_data->finish_mutex );
190
+
191
+ // I finished my race
192
+ return NULL;
193
+ }