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