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 NUM_ITEMS 127
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
Cond *nonempty;
26
Cond *nonfull;
27
} Queue;
28
29
Queue *make_queue(int length)
30
{
31
Queue *queue = (Queue *) malloc(sizeof(Queue));
32
queue->length = length;
33
queue->array = (int *) malloc(length * sizeof(int));
34
queue->next_in = 0;
35
queue->next_out = 0;
36
queue->mutex = make_mutex();
37
queue->nonempty = make_cond();
38
queue->nonfull = make_cond();
39
return queue;
40
}
41
42
int queue_incr(Queue *queue, int i)
43
{
44
return (i+1) % queue->length;
45
}
46
47
int queue_empty(Queue *queue)
48
{
49
// queue is empty if next_in and next_out are the same
50
int res = (queue->next_in == queue->next_out);
51
return res;
52
}
53
54
int queue_full(Queue *queue)
55
{
56
// queue is full if incrementing next_in lands on next_out
57
int res = (queue_incr(queue, queue->next_in) == queue->next_out);
58
return res;
59
}
60
61
void queue_push(Queue *queue, int item) {
62
mutex_lock(queue->mutex);
63
while (queue_full(queue)) {
64
cond_wait(queue->nonfull, queue->mutex);
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
cond_signal(queue->nonempty);
71
}
72
73
int queue_pop(Queue *queue) {
74
mutex_lock(queue->mutex);
75
while (queue_empty(queue)) {
76
cond_wait(queue->nonempty, queue->mutex);
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
cond_signal(queue->nonfull);
83
return item;
84
}
85
86
// SHARED
87
88
typedef struct {
89
Queue *queue;
90
} Shared;
91
92
Shared *make_shared()
93
{
94
Shared *shared = check_malloc(sizeof(Shared));
95
shared->queue = make_queue(128);
96
return shared;
97
}
98
99
// THREAD
100
101
pthread_t make_thread(void *(*entry)(void *), Shared *shared)
102
{
103
int ret;
104
pthread_t thread;
105
106
ret = pthread_create(&thread, NULL, entry, (void *) shared);
107
if (ret != 0) {
108
perror_exit("pthread_create failed");
109
}
110
return thread;
111
}
112
113
void join_thread(pthread_t thread)
114
{
115
int ret = pthread_join(thread, NULL);
116
if (ret == -1) {
117
perror_exit("pthread_join failed");
118
}
119
}
120
121
// PRODUCER-CONSUMER
122
123
void *producer_entry(void *arg)
124
{
125
int i;
126
Shared *shared = (Shared *) arg;
127
for (i=0; i<NUM_ITEMS; i++) {
128
printf("adding item %d\n", i);
129
queue_push(shared->queue, i);
130
}
131
pthread_exit(NULL);
132
}
133
134
void *consumer_entry(void *arg)
135
{
136
int i;
137
int item;
138
Shared *shared = (Shared *) arg;
139
140
for (i=0; i<NUM_ITEMS; i++) {
141
item = queue_pop(shared->queue);
142
printf("consuming item %d\n", item);
143
}
144
pthread_exit(NULL);
145
}
146
147
// TEST CODE
148
149
void queue_test()
150
{
151
int i;
152
int item;
153
int length = 128;
154
155
Queue *queue = make_queue(length);
156
assert(queue_empty(queue));
157
for (i=0; i<length-1; i++) {
158
queue_push(queue, i);
159
}
160
assert(queue_full(queue));
161
for (i=0; i<10; i++) {
162
item = queue_pop(queue);
163
assert(i == item);
164
}
165
assert(!queue_empty(queue));
166
assert(!queue_full(queue));
167
for (i=0; i<10; i++) {
168
queue_push(queue, i);
169
}
170
assert(queue_full(queue));
171
for (i=0; i<10; i++) {
172
item = queue_pop(queue);
173
}
174
assert(item == 19);
175
}
176
177
int main()
178
{
179
int i;
180
pthread_t child[NUM_CHILDREN];
181
182
Shared *shared = make_shared();
183
184
child[0] = make_thread(producer_entry, shared);
185
child[1] = make_thread(consumer_entry, shared);
186
187
for (i=0; i<NUM_CHILDREN; i++) {
188
join_thread(child[i]);
189
}
190
191
return 0;
192
}
193
194