pthreads/{hello_order_busywait/hello_order_busywait.c → position_race/position_race.c} RENAMED
@@ -1,114 +1,119 @@
1
  // Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
2
- // Creates an arbitrary amount of threads that greet in stdout
3
 
4
  #include <assert.h>
5
  #include <errno.h>
6
  #include <pthread.h>
7
  #include <stdio.h>
8
  #include <stdlib.h>
9
  #include <unistd.h>
10
 
11
 
12
  typedef struct {
13
  size_t thread_count;
14
- size_t next_thread;
 
15
  } shared_data_t;
16
 
17
  typedef struct {
18
  size_t thread_number;
19
  shared_data_t* shared_data;
20
  } private_data_t;
21
 
22
  int create_threads(shared_data_t* shared_data);
23
  void* run(void* data);
24
 
25
 
26
  int main(int argc, char* argv[]) {
27
  int error = EXIT_SUCCESS;
28
 
29
  shared_data_t* shared_data = (shared_data_t*)
30
  calloc(1, sizeof(shared_data_t));
31
 
32
  if (shared_data) {
33
- shared_data->next_thread = 0;
34
  shared_data->thread_count = sysconf(_SC_NPROCESSORS_ONLN);
 
 
35
  if (argc == 2) {
36
  if (sscanf(argv[1], "%zu", &shared_data->thread_count) != 1 || errno) {
37
  fprintf(stderr, "error: invalid thread count\n");
38
- return EXIT_FAILURE;
39
  }
40
  }
41
 
 
42
  struct timespec start_time;
43
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
44
 
45
  error = create_threads(shared_data);
46
 
47
  struct timespec finish_time;
48
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
49
 
50
  double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
51
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
52
  printf("execution time: %.9lfs\n", elapsed);
53
 
 
 
 
 
 
 
54
  free(shared_data);
55
  }
56
 
57
  return error;
58
  }
59
 
60
  int create_threads(shared_data_t* shared_data) {
61
  assert(shared_data);
62
  int error = EXIT_SUCCESS;
63
  pthread_t* threads = (pthread_t*) calloc(shared_data->thread_count
64
  , sizeof(pthread_t));
65
  private_data_t* private_data = (private_data_t*)
66
  calloc(shared_data->thread_count, sizeof(private_data_t));
67
  if (threads && private_data) {
68
  for (size_t index = 0; index < shared_data->thread_count; ++index) {
69
  private_data[index].thread_number = index;
70
  private_data[index].shared_data = shared_data;
71
  if (pthread_create(&threads[index], /*attr*/ NULL, run
72
  , &private_data[index]) == EXIT_SUCCESS) {
73
  } else {
74
  fprintf(stderr, "error: could not create thread %zu\n", index);
75
  error = 21;
76
  break;
77
  }
78
  }
79
 
80
  printf("Hello from main thread\n");
81
 
82
  for (size_t index = 0; index < shared_data->thread_count; ++index) {
83
  pthread_join(threads[index], /*value_ptr*/ NULL);
84
  }
85
  free(threads);
86
  free(private_data);
87
  } else {
88
  fprintf(stderr, "error: could not allocate memory for %zu threads\n"
89
  , shared_data->thread_count);
90
  error = 22;
91
  }
92
 
93
  return error;
94
  }
95
 
96
  void* run(void* data) {
97
  const private_data_t* private_data = (private_data_t*)data;
 
98
  const size_t my_thread_id = private_data->thread_number;
99
- const size_t thread_count = private_data->shared_data->thread_count;
100
-
101
- // Wait until it is my turn
102
- while (private_data->shared_data->next_thread < my_thread_id) {
103
- // busy-waiting
104
- }
105
-
106
- // Do the ordered-task here
107
- printf("Hello from secondary thread %zu of %zu\n", my_thread_id
108
- , thread_count);
109
 
110
- // Allow subsequent thread to do the task
111
- ++private_data->shared_data->next_thread;
 
 
 
112
 
113
  return NULL;
114
  }
1
  // Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
2
+ // Simulates a race, each thread reports its position when reaches the finish
3
 
4
  #include <assert.h>
5
  #include <errno.h>
6
  #include <pthread.h>
7
  #include <stdio.h>
8
  #include <stdlib.h>
9
  #include <unistd.h>
10
 
11
 
12
  typedef struct {
13
  size_t thread_count;
14
+ size_t position;
15
+ pthread_mutex_t can_access_position;
16
  } shared_data_t;
17
 
18
  typedef struct {
19
  size_t thread_number;
20
  shared_data_t* shared_data;
21
  } private_data_t;
22
 
23
  int create_threads(shared_data_t* shared_data);
24
  void* run(void* data);
25
 
26
 
27
  int main(int argc, char* argv[]) {
28
  int error = EXIT_SUCCESS;
29
 
30
  shared_data_t* shared_data = (shared_data_t*)
31
  calloc(1, sizeof(shared_data_t));
32
 
33
  if (shared_data) {
34
+ shared_data->position = 0;
35
  shared_data->thread_count = sysconf(_SC_NPROCESSORS_ONLN);
36
+ error = pthread_mutex_init(&shared_data->can_access_position, /*attr*/ NULL);
37
+ if (error == EXIT_SUCCESS) {
38
  if (argc == 2) {
39
  if (sscanf(argv[1], "%zu", &shared_data->thread_count) != 1 || errno) {
40
  fprintf(stderr, "error: invalid thread count\n");
41
+ error = 1;
42
  }
43
  }
44
 
45
+ if (error == EXIT_SUCCESS) {
46
  struct timespec start_time;
47
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
48
 
49
  error = create_threads(shared_data);
50
 
51
  struct timespec finish_time;
52
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
53
 
54
  double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
55
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
56
  printf("execution time: %.9lfs\n", elapsed);
57
 
58
+ pthread_mutex_destroy(&shared_data->can_access_position);
59
+ }
60
+ } else {
61
+ fprintf(stderr, "error: could not init mutex\n");
62
+ }
63
+
64
  free(shared_data);
65
  }
66
 
67
  return error;
68
  }
69
 
70
  int create_threads(shared_data_t* shared_data) {
71
  assert(shared_data);
72
  int error = EXIT_SUCCESS;
73
  pthread_t* threads = (pthread_t*) calloc(shared_data->thread_count
74
  , sizeof(pthread_t));
75
  private_data_t* private_data = (private_data_t*)
76
  calloc(shared_data->thread_count, sizeof(private_data_t));
77
  if (threads && private_data) {
78
  for (size_t index = 0; index < shared_data->thread_count; ++index) {
79
  private_data[index].thread_number = index;
80
  private_data[index].shared_data = shared_data;
81
  if (pthread_create(&threads[index], /*attr*/ NULL, run
82
  , &private_data[index]) == EXIT_SUCCESS) {
83
  } else {
84
  fprintf(stderr, "error: could not create thread %zu\n", index);
85
  error = 21;
86
  break;
87
  }
88
  }
89
 
90
  printf("Hello from main thread\n");
91
 
92
  for (size_t index = 0; index < shared_data->thread_count; ++index) {
93
  pthread_join(threads[index], /*value_ptr*/ NULL);
94
  }
95
  free(threads);
96
  free(private_data);
97
  } else {
98
  fprintf(stderr, "error: could not allocate memory for %zu threads\n"
99
  , shared_data->thread_count);
100
  error = 22;
101
  }
102
 
103
  return error;
104
  }
105
 
106
  void* run(void* data) {
107
  const private_data_t* private_data = (private_data_t*)data;
108
+ shared_data_t* shared_data = private_data->shared_data;
109
  const size_t my_thread_id = private_data->thread_number;
110
+ const size_t thread_count = shared_data->thread_count;
 
 
 
 
 
 
 
 
 
111
 
112
+ pthread_mutex_lock(&shared_data->can_access_position);
113
+ size_t my_position = ++shared_data->position;
114
+ printf("Thread %zu/%zu: I arrived at position %zu\n", my_thread_id
115
+ , thread_count, my_position);
116
+ pthread_mutex_unlock(&shared_data->can_access_position);
117
 
118
  return NULL;
119
  }