📚 The CoCalc Library - books, templates and other resources
License: OTHER
/* Example code for Think OS.12Copyright 2015 Allen Downey3License: Creative Commons Attribution-ShareAlike 3.045*/67#include <stdio.h>8#include <stdlib.h>9#include <assert.h>10#include <pthread.h>11#include "utils.h"1213#define NUM_CHILDREN 214#define QUEUE_LENGTH 161516// QUEUE1718typedef struct {19int *array;20int length;21int next_in;22int next_out;23Mutex *mutex;24} Queue;2526Queue *make_queue(int length)27{28Queue *queue = (Queue *) malloc(sizeof(Queue));29queue->length = length;30queue->array = (int *) malloc(length * sizeof(int));31queue->next_in = 0;32queue->next_out = 0;33queue->mutex = make_mutex();34return queue;35}3637int queue_incr(Queue *queue, int i)38{39// NOTE: you must hold the mutex to call this function.40return (i+1) % queue->length;41}4243int queue_empty(Queue *queue)44{45// NOTE: you must hold the mutex to call this function.46// queue is empty if next_in and next_out are the same47int res = (queue->next_in == queue->next_out);48return res;49}5051int queue_full(Queue *queue)52{53// NOTE: you must hold the mutex to call this function.54// queue is full if incrementing next_in lands on next_out55int res = (queue_incr(queue, queue->next_in) == queue->next_out);56return res;57}5859void queue_push(Queue *queue, int item) {60mutex_lock(queue->mutex);61if (queue_full(queue)) {62mutex_unlock(queue->mutex);63perror_exit("queue is full");64}6566queue->array[queue->next_in] = item;67queue->next_in = queue_incr(queue, queue->next_in);68mutex_unlock(queue->mutex);69}7071int queue_pop(Queue *queue) {72mutex_lock(queue->mutex);73if (queue_empty(queue)) {74mutex_unlock(queue->mutex);75perror_exit("queue is empty");76}7778int item = queue->array[queue->next_out];79queue->next_out = queue_incr(queue, queue->next_out);80mutex_unlock(queue->mutex);81return item;82}8384// SHARED8586typedef struct {87Queue *queue;88} Shared;8990Shared *make_shared()91{92Shared *shared = check_malloc(sizeof(Shared));93shared->queue = make_queue(QUEUE_LENGTH);94return shared;95}9697// THREAD9899pthread_t make_thread(void *(*entry)(void *), Shared *shared)100{101int ret;102pthread_t thread;103104ret = pthread_create(&thread, NULL, entry, (void *) shared);105if (ret != 0) {106perror_exit("pthread_create failed");107}108return thread;109}110111void join_thread(pthread_t thread)112{113int ret = pthread_join(thread, NULL);114if (ret == -1) {115perror_exit("pthread_join failed");116}117}118119// PRODUCER-CONSUMER120121void *producer_entry(void *arg)122{123int i;124Shared *shared = (Shared *) arg;125for (i=0; i<QUEUE_LENGTH; i++) {126printf("adding item %d\n", i);127queue_push(shared->queue, i);128}129pthread_exit(NULL);130}131132void *consumer_entry(void *arg)133{134int i;135int item;136Shared *shared = (Shared *) arg;137138for (i=0; i<QUEUE_LENGTH; i++) {139item = queue_pop(shared->queue);140printf("consuming item %d\n", item);141}142pthread_exit(NULL);143}144145// TEST CODE146147void queue_test()148{149int i;150int item;151int length = 128;152153Queue *queue = make_queue(length);154assert(queue_empty(queue));155for (i=0; i<length-1; i++) {156queue_push(queue, i);157}158assert(queue_full(queue));159for (i=0; i<10; i++) {160item = queue_pop(queue);161assert(i == item);162}163assert(!queue_empty(queue));164assert(!queue_full(queue));165for (i=0; i<10; i++) {166queue_push(queue, i);167}168assert(queue_full(queue));169for (i=0; i<10; i++) {170item = queue_pop(queue);171}172assert(item == 19);173}174175int main()176{177int i;178pthread_t child[NUM_CHILDREN];179180Shared *shared = make_shared();181182child[0] = make_thread(producer_entry, shared);183child[1] = make_thread(consumer_entry, shared);184185for (i=0; i<NUM_CHILDREN; i++) {186join_thread(child[i]);187}188189return 0;190}191192193