1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 | // Copyright 2021 Jeisson Hidalgo-Cespedes <jeisson.hidalgo@ucr.ac.cr> CC-BY-4
// All threads greet in their rank order by using an array of semaphores
// After greeting a thread turns on the next thread's semaphore
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct {
size_t thread_count;
size_t position;
sem_t* can_greet;
} shared_data_t;
typedef struct {
size_t thread_number;
shared_data_t* shared_data;
} private_data_t;
int measure_greet(shared_data_t* shared_data);
int create_threads(shared_data_t* shared_data);
void* run(void* data);
int main(int argc, char* argv[]) {
int error = EXIT_SUCCESS;
shared_data_t* shared_data = (shared_data_t*)
calloc(1, sizeof(shared_data_t));
if (shared_data) {
shared_data->position = 0;
shared_data->thread_count = sysconf(_SC_NPROCESSORS_ONLN);
if (argc == 2) {
if (sscanf(argv[1], "%zu", &shared_data->thread_count) != 1 || errno) {
fprintf(stderr, "error: invalid thread count\n");
error = 1;
}
}
if (error == EXIT_SUCCESS) {
shared_data->can_greet = (sem_t*) calloc(shared_data->thread_count
, sizeof(sem_t));
if (shared_data->can_greet) {
error = measure_greet(shared_data);
free(shared_data->can_greet);
} else {
fprintf(stderr, "error: could not allocate semaphores\n");
error = 3;
}
free(shared_data);
} else {
fprintf(stderr, "error: could not allocate shared memory\n");
error = 2;
}
}
return error;
}
int measure_greet(shared_data_t* shared_data) {
struct timespec start_time;
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &start_time);
int error = create_threads(shared_data);
struct timespec finish_time;
clock_gettime(/*clk_id*/CLOCK_MONOTONIC, &finish_time);
double elapsed = (finish_time.tv_sec - start_time.tv_sec) +
(finish_time.tv_nsec - start_time.tv_nsec) * 1e-9;
printf("execution time: %.9lfs\n", elapsed);
return error;
}
int create_threads(shared_data_t* shared_data) {
assert(shared_data);
int error = EXIT_SUCCESS;
pthread_t* threads = (pthread_t*) calloc(shared_data->thread_count
, sizeof(pthread_t));
private_data_t* private_data = (private_data_t*)
calloc(shared_data->thread_count, sizeof(private_data_t));
if (threads && private_data) {
for (size_t index = 0; index < shared_data->thread_count; ++index) {
private_data[index].thread_number = index;
private_data[index].shared_data = shared_data;
error = sem_init(&shared_data->can_greet[index], /*pshared*/ 0
, /*value*/ !index);
if (error == EXIT_SUCCESS) {
if (pthread_create(&threads[index], /*attr*/ NULL, run
, &private_data[index]) == EXIT_SUCCESS) {
} else {
fprintf(stderr, "error: could not create thread %zu\n", index);
error = 21;
shared_data->thread_count = index;
break;
}
} else {
fprintf(stderr, "error: could not init semaphore %zu\n", index);
error = 22;
shared_data->thread_count = index;
break;
}
}
printf("Hello from main thread\n");
for (size_t index = 0; index < shared_data->thread_count; ++index) {
pthread_join(threads[index], /*value_ptr*/ NULL);
sem_destroy(&shared_data->can_greet[index]);
}
free(threads);
free(private_data);
} else {
fprintf(stderr, "error: could not allocate memory for %zu threads\n"
, shared_data->thread_count);
error = 22;
}
return error;
}
void* run(void* data) {
const private_data_t* private_data = (private_data_t*)data;
shared_data_t* shared_data = private_data->shared_data;
const size_t my_thread_id = private_data->thread_number;
const size_t thread_count = shared_data->thread_count;
sem_wait(&shared_data->can_greet[my_thread_id]);
printf("Hello from thread %zu of %zu\n", my_thread_id, thread_count);
sem_post(&shared_data->can_greet[(my_thread_id + 1) % thread_count]);
return NULL;
}
|