pthreads/prod_cons_unbound/{given → src}/simulation.c RENAMED
@@ -1,145 +1,151 @@
1
  // Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
2
 
3
  #include <assert.h>
4
  #include <errno.h>
5
  #include <pthread.h>
6
  #include <stdlib.h>
7
  #include <sys/random.h>
8
  #include <stdio.h>
9
 
10
  #include "common.h"
11
  #include "consumer.h"
12
  #include "producer.h"
13
  #include "simulation.h"
14
 
15
  int analyze_arguments(simulation_t* simulation, int argc, char* argv[]);
16
  int create_consumers_producers(simulation_t* simulation);
17
  int join_threads(size_t count, pthread_t* threads);
18
 
19
  simulation_t* simulation_create() {
20
  simulation_t* simulation = (simulation_t*) calloc(1, sizeof(simulation_t));
21
  if (simulation) {
22
  simulation->unit_count = 0;
23
  simulation->producer_count = 0;
24
  simulation->consumer_count = 0;
25
  simulation->producer_min_delay = 0;
26
  simulation->producer_max_delay = 0;
27
  simulation->consumer_min_delay = 0;
28
  simulation->consumer_max_delay = 0;
29
  queue_init(&simulation->queue);
 
30
  simulation->next_unit = 0;
 
 
31
  simulation->consumed_count = 0;
32
  }
33
  return simulation;
34
  }
35
 
36
  void simulation_destroy(simulation_t* simulation) {
37
  assert(simulation);
 
 
 
38
  queue_destroy(&simulation->queue);
39
  free(simulation);
40
  }
41
 
42
  int simulation_run(simulation_t* simulation, int argc, char* argv[]) {
43
  int error = analyze_arguments(simulation, argc, argv);
44
  if (error == EXIT_SUCCESS) {
45
  unsigned int seed = 0;
46
  getrandom(&seed, sizeof(seed), GRND_NONBLOCK);
47
  srandom(seed);
48
 
49
  struct timespec start_time;
50
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
51
 
52
  error = create_consumers_producers(simulation);
53
 
54
  struct timespec finish_time;
55
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
56
 
57
  double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
58
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
59
  printf("execution time: %.9lfs\n", elapsed);
60
  }
61
  return error;
62
  }
63
 
64
  int analyze_arguments(simulation_t* simulation, int argc, char* argv[]) {
65
  int error = EXIT_SUCCESS;
66
  if (argc == 8) {
67
  if (sscanf(argv[1], "%zu", &simulation->unit_count) != 1
68
  || simulation->unit_count == 0) {
69
  fprintf(stderr, "error: invalid unit count\n");
70
  error = ERR_UNIT_COUNT;
71
  } else if (sscanf(argv[2], "%zu", &simulation->producer_count) != 1
72
  || simulation->producer_count == 0) {
73
  fprintf(stderr, "error: invalid producer count\n");
74
  error = ERR_PRODUCER_COUNT;
75
  } else if (sscanf(argv[3], "%zu", &simulation->consumer_count) != 1
76
  || simulation->consumer_count == 0) {
77
  fprintf(stderr, "error: invalid consumer count\n");
78
  error = ERR_CONSUMER_COUNT;
79
  } else if (sscanf(argv[4], "%u", &simulation->producer_min_delay) != 1) {
80
  fprintf(stderr, "error: invalid min producer delay\n");
81
  error = ERR_MIN_PROD_DELAY;
82
  } else if (sscanf(argv[5], "%u", &simulation->producer_max_delay) != 1) {
83
  fprintf(stderr, "error: invalid max producer delay\n");
84
  error = ERR_MAX_PROD_DELAY;
85
  } else if (sscanf(argv[6], "%u", &simulation->consumer_min_delay) != 1) {
86
  fprintf(stderr, "error: invalid min consumer delay\n");
87
  error = ERR_MIN_CONS_DELAY;
88
  } else if (sscanf(argv[7], "%u", &simulation->consumer_max_delay) != 1) {
89
  fprintf(stderr, "error: invalid max consumer delay\n");
90
  error = ERR_MAX_CONS_DELAY;
91
  }
92
  } else {
93
  fprintf(stderr, "usage: producer_consumer buffer_capacity rounds"
94
  " producer_min_delay producer_max_delay"
95
  " consumer_min_delay consumer_max_delay\n");
96
  error = ERR_NO_ARGS;
97
  }
98
  return error;
99
  }
100
 
101
  pthread_t* create_threads(size_t count, void*(*subroutine)(void*), void* data) {
102
  pthread_t* threads = (pthread_t*) calloc(count, sizeof(pthread_t));
103
  if (threads) {
104
  for (size_t index = 0; index < count; ++index) {
105
  if (pthread_create(&threads[index], /*attr*/ NULL, subroutine, data)
106
  == EXIT_SUCCESS) {
107
  } else {
108
  fprintf(stderr, "error: could not create thread %zu\n", index);
109
  join_threads(index, threads);
110
  return NULL;
111
  }
112
  }
113
  }
114
  return threads;
115
  }
116
 
117
  int join_threads(size_t count, pthread_t* threads) {
118
  int error = EXIT_SUCCESS;
119
  for (size_t index = 0; index < count; ++index) {
120
  // todo: sum could not be right
121
  error += pthread_join(threads[index], /*value_ptr*/ NULL);
122
  }
123
  free(threads);
124
  return error;
125
  }
126
 
127
  int create_consumers_producers(simulation_t* simulation) {
128
  assert(simulation);
129
  int error = EXIT_SUCCESS;
130
 
131
  pthread_t* producers = create_threads(simulation->producer_count, produce
132
  , simulation);
133
  pthread_t* consumers = create_threads(simulation->consumer_count, consume
134
  , simulation);
135
 
136
  if (producers && consumers) {
137
  join_threads(simulation->producer_count, producers);
138
  join_threads(simulation->consumer_count, consumers);
139
  } else {
140
  fprintf(stderr, "error: could not create threads\n");
141
  error = ERR_CREATE_THREAD;
142
  }
143
 
144
  return error;
145
  }
1
  // Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
2
 
3
  #include <assert.h>
4
  #include <errno.h>
5
  #include <pthread.h>
6
  #include <stdlib.h>
7
  #include <sys/random.h>
8
  #include <stdio.h>
9
 
10
  #include "common.h"
11
  #include "consumer.h"
12
  #include "producer.h"
13
  #include "simulation.h"
14
 
15
  int analyze_arguments(simulation_t* simulation, int argc, char* argv[]);
16
  int create_consumers_producers(simulation_t* simulation);
17
  int join_threads(size_t count, pthread_t* threads);
18
 
19
  simulation_t* simulation_create() {
20
  simulation_t* simulation = (simulation_t*) calloc(1, sizeof(simulation_t));
21
  if (simulation) {
22
  simulation->unit_count = 0;
23
  simulation->producer_count = 0;
24
  simulation->consumer_count = 0;
25
  simulation->producer_min_delay = 0;
26
  simulation->producer_max_delay = 0;
27
  simulation->consumer_min_delay = 0;
28
  simulation->consumer_max_delay = 0;
29
  queue_init(&simulation->queue);
30
+ pthread_mutex_init(&simulation->can_access_next_unit, /* attr */ NULL);
31
  simulation->next_unit = 0;
32
+ sem_init(&simulation->can_consume, /* pshared */ 0, /* value */ 0);
33
+ pthread_mutex_init(&simulation->can_access_consumed_count, /* attr */ NULL);
34
  simulation->consumed_count = 0;
35
  }
36
  return simulation;
37
  }
38
 
39
  void simulation_destroy(simulation_t* simulation) {
40
  assert(simulation);
41
+ pthread_mutex_destroy(&simulation->can_access_consumed_count);
42
+ sem_destroy(&simulation->can_consume);
43
+ pthread_mutex_destroy(&simulation->can_access_next_unit);
44
  queue_destroy(&simulation->queue);
45
  free(simulation);
46
  }
47
 
48
  int simulation_run(simulation_t* simulation, int argc, char* argv[]) {
49
  int error = analyze_arguments(simulation, argc, argv);
50
  if (error == EXIT_SUCCESS) {
51
  unsigned int seed = 0;
52
  getrandom(&seed, sizeof(seed), GRND_NONBLOCK);
53
  srandom(seed);
54
 
55
  struct timespec start_time;
56
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
57
 
58
  error = create_consumers_producers(simulation);
59
 
60
  struct timespec finish_time;
61
  clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
62
 
63
  double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
64
  (finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
65
  printf("execution time: %.9lfs\n", elapsed);
66
  }
67
  return error;
68
  }
69
 
70
  int analyze_arguments(simulation_t* simulation, int argc, char* argv[]) {
71
  int error = EXIT_SUCCESS;
72
  if (argc == 8) {
73
  if (sscanf(argv[1], "%zu", &simulation->unit_count) != 1
74
  || simulation->unit_count == 0) {
75
  fprintf(stderr, "error: invalid unit count\n");
76
  error = ERR_UNIT_COUNT;
77
  } else if (sscanf(argv[2], "%zu", &simulation->producer_count) != 1
78
  || simulation->producer_count == 0) {
79
  fprintf(stderr, "error: invalid producer count\n");
80
  error = ERR_PRODUCER_COUNT;
81
  } else if (sscanf(argv[3], "%zu", &simulation->consumer_count) != 1
82
  || simulation->consumer_count == 0) {
83
  fprintf(stderr, "error: invalid consumer count\n");
84
  error = ERR_CONSUMER_COUNT;
85
  } else if (sscanf(argv[4], "%u", &simulation->producer_min_delay) != 1) {
86
  fprintf(stderr, "error: invalid min producer delay\n");
87
  error = ERR_MIN_PROD_DELAY;
88
  } else if (sscanf(argv[5], "%u", &simulation->producer_max_delay) != 1) {
89
  fprintf(stderr, "error: invalid max producer delay\n");
90
  error = ERR_MAX_PROD_DELAY;
91
  } else if (sscanf(argv[6], "%u", &simulation->consumer_min_delay) != 1) {
92
  fprintf(stderr, "error: invalid min consumer delay\n");
93
  error = ERR_MIN_CONS_DELAY;
94
  } else if (sscanf(argv[7], "%u", &simulation->consumer_max_delay) != 1) {
95
  fprintf(stderr, "error: invalid max consumer delay\n");
96
  error = ERR_MAX_CONS_DELAY;
97
  }
98
  } else {
99
  fprintf(stderr, "usage: producer_consumer buffer_capacity rounds"
100
  " producer_min_delay producer_max_delay"
101
  " consumer_min_delay consumer_max_delay\n");
102
  error = ERR_NO_ARGS;
103
  }
104
  return error;
105
  }
106
 
107
  pthread_t* create_threads(size_t count, void*(*subroutine)(void*), void* data) {
108
  pthread_t* threads = (pthread_t*) calloc(count, sizeof(pthread_t));
109
  if (threads) {
110
  for (size_t index = 0; index < count; ++index) {
111
  if (pthread_create(&threads[index], /*attr*/ NULL, subroutine, data)
112
  == EXIT_SUCCESS) {
113
  } else {
114
  fprintf(stderr, "error: could not create thread %zu\n", index);
115
  join_threads(index, threads);
116
  return NULL;
117
  }
118
  }
119
  }
120
  return threads;
121
  }
122
 
123
  int join_threads(size_t count, pthread_t* threads) {
124
  int error = EXIT_SUCCESS;
125
  for (size_t index = 0; index < count; ++index) {
126
  // todo: sum could not be right
127
  error += pthread_join(threads[index], /*value_ptr*/ NULL);
128
  }
129
  free(threads);
130
  return error;
131
  }
132
 
133
  int create_consumers_producers(simulation_t* simulation) {
134
  assert(simulation);
135
  int error = EXIT_SUCCESS;
136
 
137
  pthread_t* producers = create_threads(simulation->producer_count, produce
138
  , simulation);
139
  pthread_t* consumers = create_threads(simulation->consumer_count, consume
140
  , simulation);
141
 
142
  if (producers && consumers) {
143
  join_threads(simulation->producer_count, producers);
144
  join_threads(simulation->consumer_count, consumers);
145
  } else {
146
  fprintf(stderr, "error: could not create threads\n");
147
  error = ERR_CREATE_THREAD;
148
  }
149
 
150
  return error;
151
  }