Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

📚 The CoCalc Library - books, templates and other resources

132928 views
License: OTHER
1
/* Example code for Think OS.
2
3
Copyright 2015 Allen Downey
4
License: Creative Commons Attribution-ShareAlike 3.0
5
6
*/
7
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <assert.h>
11
#include <pthread.h>
12
#include "utils.h"
13
14
#define NUM_CHILDREN 2
15
#define QUEUE_LENGTH 16
16
17
// QUEUE
18
19
typedef struct {
20
int *array;
21
int length;
22
int next_in;
23
int next_out;
24
Mutex *mutex;
25
} Queue;
26
27
Queue *make_queue(int length)
28
{
29
Queue *queue = (Queue *) malloc(sizeof(Queue));
30
queue->length = length;
31
queue->array = (int *) malloc(length * sizeof(int));
32
queue->next_in = 0;
33
queue->next_out = 0;
34
queue->mutex = make_mutex();
35
return queue;
36
}
37
38
int queue_incr(Queue *queue, int i)
39
{
40
// NOTE: you must hold the mutex to call this function.
41
return (i+1) % queue->length;
42
}
43
44
int queue_empty(Queue *queue)
45
{
46
// NOTE: you must hold the mutex to call this function.
47
// queue is empty if next_in and next_out are the same
48
int res = (queue->next_in == queue->next_out);
49
return res;
50
}
51
52
int queue_full(Queue *queue)
53
{
54
// NOTE: you must hold the mutex to call this function.
55
// queue is full if incrementing next_in lands on next_out
56
int res = (queue_incr(queue, queue->next_in) == queue->next_out);
57
return res;
58
}
59
60
void queue_push(Queue *queue, int item) {
61
mutex_lock(queue->mutex);
62
if (queue_full(queue)) {
63
mutex_unlock(queue->mutex);
64
perror_exit("queue is full");
65
}
66
67
queue->array[queue->next_in] = item;
68
queue->next_in = queue_incr(queue, queue->next_in);
69
mutex_unlock(queue->mutex);
70
}
71
72
int queue_pop(Queue *queue) {
73
mutex_lock(queue->mutex);
74
if (queue_empty(queue)) {
75
mutex_unlock(queue->mutex);
76
perror_exit("queue is empty");
77
}
78
79
int item = queue->array[queue->next_out];
80
queue->next_out = queue_incr(queue, queue->next_out);
81
mutex_unlock(queue->mutex);
82
return item;
83
}
84
85
// SHARED
86
87
typedef struct {
88
Queue *queue;
89
} Shared;
90
91
Shared *make_shared()
92
{
93
Shared *shared = check_malloc(sizeof(Shared));
94
shared->queue = make_queue(QUEUE_LENGTH);
95
return shared;
96
}
97
98
// THREAD
99
100
pthread_t make_thread(void *(*entry)(void *), Shared *shared)
101
{
102
int ret;
103
pthread_t thread;
104
105
ret = pthread_create(&thread, NULL, entry, (void *) shared);
106
if (ret != 0) {
107
perror_exit("pthread_create failed");
108
}
109
return thread;
110
}
111
112
void join_thread(pthread_t thread)
113
{
114
int ret = pthread_join(thread, NULL);
115
if (ret == -1) {
116
perror_exit("pthread_join failed");
117
}
118
}
119
120
// PRODUCER-CONSUMER
121
122
void *producer_entry(void *arg)
123
{
124
int i;
125
Shared *shared = (Shared *) arg;
126
for (i=0; i<QUEUE_LENGTH; i++) {
127
printf("adding item %d\n", i);
128
queue_push(shared->queue, i);
129
}
130
pthread_exit(NULL);
131
}
132
133
void *consumer_entry(void *arg)
134
{
135
int i;
136
int item;
137
Shared *shared = (Shared *) arg;
138
139
for (i=0; i<QUEUE_LENGTH; i++) {
140
item = queue_pop(shared->queue);
141
printf("consuming item %d\n", item);
142
}
143
pthread_exit(NULL);
144
}
145
146
// TEST CODE
147
148
void queue_test()
149
{
150
int i;
151
int item;
152
int length = 128;
153
154
Queue *queue = make_queue(length);
155
assert(queue_empty(queue));
156
for (i=0; i<length-1; i++) {
157
queue_push(queue, i);
158
}
159
assert(queue_full(queue));
160
for (i=0; i<10; i++) {
161
item = queue_pop(queue);
162
assert(i == item);
163
}
164
assert(!queue_empty(queue));
165
assert(!queue_full(queue));
166
for (i=0; i<10; i++) {
167
queue_push(queue, i);
168
}
169
assert(queue_full(queue));
170
for (i=0; i<10; i++) {
171
item = queue_pop(queue);
172
}
173
assert(item == 19);
174
}
175
176
int main()
177
{
178
int i;
179
pthread_t child[NUM_CHILDREN];
180
181
Shared *shared = make_shared();
182
183
child[0] = make_thread(producer_entry, shared);
184
child[1] = make_thread(consumer_entry, shared);
185
186
for (i=0; i<NUM_CHILDREN; i++) {
187
join_thread(child[i]);
188
}
189
190
return 0;
191
}
192
193