pthreads/{hello_order_busywait/src/hello_order_busywait.c → position_race/src/position_race.c} RENAMED
@@ -1,130 +1,140 @@
1
  // Copyright 2021 Jeisson Hidalgo <jeisson.hidalgo@ucr.ac.cr> CC-BY 4.0
2
 
3
  #include <assert.h>
4
  #include <inttypes.h>
5
  #include <pthread.h>
6
  #include <stdint.h>
7
  #include <stdio.h>
8
  #include <stdlib.h>
9
  #include <time.h>
10
  #include <unistd.h>
11
 
12
  // thread_shared_data_t
13
  typedef struct shared_data {
14
- uint64_t next_thread;
 
15
  uint64_t thread_count;
16
  } shared_data_t;
17
 
18
  // thread_private_data_t
19
  typedef struct private_data {
20
  uint64_t thread_number; // rank
21
  shared_data_t* shared_data;
22
  } private_data_t;
23
 
24
  /**
25
  * @brief ...
26
  */
27
- void* greet(void* data);
28
  int create_threads(shared_data_t* shared_data);
29
 
30
  // procedure main(argc, argv[])
31
  int main(int argc, char* argv[]) {
32
  int error = EXIT_SUCCESS;
33
  // create thread_count as result of converting argv[1] to integer
34
  // thread_count := integer(argv[1])
35
  uint64_t thread_count = sysconf(_SC_NPROCESSORS_ONLN);
36
  if (argc == 2) {
37
  if (sscanf(argv[1], "%" SCNu64, &thread_count) == 1) {
38
  } else {
39
  fprintf(stderr, "Error: invalid thread count\n");
40
  return 11;
41
  }
42
  }
43
 
44
  shared_data_t* shared_data = (shared_data_t*)calloc(1, sizeof(shared_data_t));
45
  if (shared_data) {
46
- shared_data->next_thread = 0;
 
 
47
  shared_data->thread_count = thread_count;
48
 
49
  struct timespec start_time, finish_time;
50
  clock_gettime(CLOCK_MONOTONIC, &start_time);
51
 
52
  error = create_threads(shared_data);
53
 
54
  clock_gettime(CLOCK_MONOTONIC, &finish_time);
55
  double elapsed_time = finish_time.tv_sec - start_time.tv_sec +
56
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
57
 
58
  printf("Execution time: %.9lfs\n", elapsed_time);
59
 
 
60
  free(shared_data);
61
  } else {
 
 
 
 
62
  fprintf(stderr, "Error: could not allocate shared data\n");
63
  return 12;
64
  }
65
  return error;
66
  } // end procedure
67
 
68
 
69
  int create_threads(shared_data_t* shared_data) {
70
  int error = EXIT_SUCCESS;
71
  // for thread_number := 0 to thread_count do
72
  pthread_t* threads = (pthread_t*)
73
  malloc(shared_data->thread_count * sizeof(pthread_t));
74
  private_data_t* private_data = (private_data_t*)
75
  calloc(shared_data->thread_count, sizeof(private_data_t));
76
  if (threads && private_data) {
77
  for (uint64_t thread_number = 0; thread_number < shared_data->thread_count
78
  ; ++thread_number) {
79
  private_data[thread_number].thread_number = thread_number;
80
  private_data[thread_number].shared_data = shared_data;
81
  // create_thread(greet, thread_number)
82
- error = pthread_create(&threads[thread_number], /*attr*/ NULL, greet
83
  , /*arg*/ &private_data[thread_number]);
84
  if (error == EXIT_SUCCESS) {
85
  } else {
86
  fprintf(stderr, "Error: could not create secondary thread\n");
87
  error = 21;
88
  break;
89
  }
90
  }
91
 
92
  // print "Hello from main thread"
93
  printf("Hello from main thread\n");
94
 
95
  for (uint64_t thread_number = 0; thread_number < shared_data->thread_count
96
  ; ++thread_number) {
97
  pthread_join(threads[thread_number], /*value_ptr*/ NULL);
98
  }
99
 
100
  free(private_data);
101
  free(threads);
102
  } else {
103
  fprintf(stderr, "Error: could not allocate %" PRIu64 " threads\n"
104
  , shared_data->thread_count);
105
  error = 22;
106
  }
107
 
108
  return error;
109
  }
110
 
111
  // procedure greet:
112
- void* greet(void* data) {
113
  assert(data);
114
  private_data_t* private_data = (private_data_t*) data;
115
  shared_data_t* shared_data = private_data->shared_data;
116
 
117
- // Wait until it is my turn
118
- while (shared_data->next_thread < private_data->thread_number) {
119
- // busy-waiting
120
- } // end while
121
-
 
 
 
122
  // print "Hello from secondary thread"
123
- printf("Hello from secondary thread %" PRIu64 " of %" PRIu64 "\n"
124
- , private_data->thread_number, shared_data->thread_count);
125
-
126
- // Allow subsequent thread to do the task
127
- ++shared_data->next_thread;
128
 
 
 
129
  return NULL;
130
  } // end procedure
1
  // Copyright 2021 Jeisson Hidalgo <jeisson.hidalgo@ucr.ac.cr> CC-BY 4.0
2
 
3
  #include <assert.h>
4
  #include <inttypes.h>
5
  #include <pthread.h>
6
  #include <stdint.h>
7
  #include <stdio.h>
8
  #include <stdlib.h>
9
  #include <time.h>
10
  #include <unistd.h>
11
 
12
  // thread_shared_data_t
13
  typedef struct shared_data {
14
+ uint64_t position;
15
+ pthread_mutex_t can_access_position;
16
  uint64_t thread_count;
17
  } shared_data_t;
18
 
19
  // thread_private_data_t
20
  typedef struct private_data {
21
  uint64_t thread_number; // rank
22
  shared_data_t* shared_data;
23
  } private_data_t;
24
 
25
  /**
26
  * @brief ...
27
  */
28
+ void* race(void* data);
29
  int create_threads(shared_data_t* shared_data);
30
 
31
  // procedure main(argc, argv[])
32
  int main(int argc, char* argv[]) {
33
  int error = EXIT_SUCCESS;
34
  // create thread_count as result of converting argv[1] to integer
35
  // thread_count := integer(argv[1])
36
  uint64_t thread_count = sysconf(_SC_NPROCESSORS_ONLN);
37
  if (argc == 2) {
38
  if (sscanf(argv[1], "%" SCNu64, &thread_count) == 1) {
39
  } else {
40
  fprintf(stderr, "Error: invalid thread count\n");
41
  return 11;
42
  }
43
  }
44
 
45
  shared_data_t* shared_data = (shared_data_t*)calloc(1, sizeof(shared_data_t));
46
  if (shared_data) {
47
+ shared_data->position = 0;
48
+ error = pthread_mutex_init(&shared_data->can_access_position, /*attr*/NULL);
49
+ if (error == EXIT_SUCCESS) {
50
  shared_data->thread_count = thread_count;
51
 
52
  struct timespec start_time, finish_time;
53
  clock_gettime(CLOCK_MONOTONIC, &start_time);
54
 
55
  error = create_threads(shared_data);
56
 
57
  clock_gettime(CLOCK_MONOTONIC, &finish_time);
58
  double elapsed_time = finish_time.tv_sec - start_time.tv_sec +
59
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
60
 
61
  printf("Execution time: %.9lfs\n", elapsed_time);
62
 
63
+ pthread_mutex_destroy(&shared_data->can_access_position);
64
  free(shared_data);
65
  } else {
66
+ fprintf(stderr, "Error: could not init mutex\n");
67
+ return 13;
68
+ }
69
+ } else {
70
  fprintf(stderr, "Error: could not allocate shared data\n");
71
  return 12;
72
  }
73
  return error;
74
  } // end procedure
75
 
76
 
77
  int create_threads(shared_data_t* shared_data) {
78
  int error = EXIT_SUCCESS;
79
  // for thread_number := 0 to thread_count do
80
  pthread_t* threads = (pthread_t*)
81
  malloc(shared_data->thread_count * sizeof(pthread_t));
82
  private_data_t* private_data = (private_data_t*)
83
  calloc(shared_data->thread_count, sizeof(private_data_t));
84
  if (threads && private_data) {
85
  for (uint64_t thread_number = 0; thread_number < shared_data->thread_count
86
  ; ++thread_number) {
87
  private_data[thread_number].thread_number = thread_number;
88
  private_data[thread_number].shared_data = shared_data;
89
  // create_thread(greet, thread_number)
90
+ error = pthread_create(&threads[thread_number], /*attr*/ NULL, race
91
  , /*arg*/ &private_data[thread_number]);
92
  if (error == EXIT_SUCCESS) {
93
  } else {
94
  fprintf(stderr, "Error: could not create secondary thread\n");
95
  error = 21;
96
  break;
97
  }
98
  }
99
 
100
  // print "Hello from main thread"
101
  printf("Hello from main thread\n");
102
 
103
  for (uint64_t thread_number = 0; thread_number < shared_data->thread_count
104
  ; ++thread_number) {
105
  pthread_join(threads[thread_number], /*value_ptr*/ NULL);
106
  }
107
 
108
  free(private_data);
109
  free(threads);
110
  } else {
111
  fprintf(stderr, "Error: could not allocate %" PRIu64 " threads\n"
112
  , shared_data->thread_count);
113
  error = 22;
114
  }
115
 
116
  return error;
117
  }
118
 
119
  // procedure greet:
120
+ void* race(void* data) {
121
  assert(data);
122
  private_data_t* private_data = (private_data_t*) data;
123
  shared_data_t* shared_data = private_data->shared_data;
124
 
125
+ // lock(can_access_position)
126
+ pthread_mutex_lock(&shared_data->can_access_position);
127
+ // race condition/data race/condición de carrera:
128
+ // modificación concurrente de memoria compartida
129
+ // position := position + 1
130
+ ++shared_data->position;
131
+ // my_position := position
132
+ uint64_t my_position = shared_data->position;
133
  // print "Hello from secondary thread"
134
+ printf("Thread %" PRIu64 "/%" PRIu64 ": I arrived at position %" PRIu64 "\n"
135
+ , private_data->thread_number, shared_data->thread_count, my_position);
 
 
 
136
 
137
+ // unlock(can_access_position)
138
+ pthread_mutex_unlock(&shared_data->can_access_position);
139
  return NULL;
140
  } // end procedure