📚 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 NUM_ITEMS 1271516// QUEUE1718typedef struct {19int *array;20int length;21int next_in;22int next_out;23Mutex *mutex;24Cond *nonempty;25Cond *nonfull;26} Queue;2728Queue *make_queue(int length)29{30Queue *queue = (Queue *) malloc(sizeof(Queue));31queue->length = length;32queue->array = (int *) malloc(length * sizeof(int));33queue->next_in = 0;34queue->next_out = 0;35queue->mutex = make_mutex();36queue->nonempty = make_cond();37queue->nonfull = make_cond();38return queue;39}4041int queue_incr(Queue *queue, int i)42{43return (i+1) % queue->length;44}4546int queue_empty(Queue *queue)47{48// queue is empty if next_in and next_out are the same49int res = (queue->next_in == queue->next_out);50return res;51}5253int queue_full(Queue *queue)54{55// queue is full if incrementing next_in lands on next_out56int res = (queue_incr(queue, queue->next_in) == queue->next_out);57return res;58}5960void queue_push(Queue *queue, int item) {61mutex_lock(queue->mutex);62while (queue_full(queue)) {63cond_wait(queue->nonfull, queue->mutex);64}6566queue->array[queue->next_in] = item;67queue->next_in = queue_incr(queue, queue->next_in);68mutex_unlock(queue->mutex);69cond_signal(queue->nonempty);70}7172int queue_pop(Queue *queue) {73mutex_lock(queue->mutex);74while (queue_empty(queue)) {75cond_wait(queue->nonempty, queue->mutex);76}7778int item = queue->array[queue->next_out];79queue->next_out = queue_incr(queue, queue->next_out);80mutex_unlock(queue->mutex);81cond_signal(queue->nonfull);82return item;83}8485// SHARED8687typedef struct {88Queue *queue;89} Shared;9091Shared *make_shared()92{93Shared *shared = check_malloc(sizeof(Shared));94shared->queue = make_queue(128);95return shared;96}9798// THREAD99100pthread_t make_thread(void *(*entry)(void *), Shared *shared)101{102int ret;103pthread_t thread;104105ret = pthread_create(&thread, NULL, entry, (void *) shared);106if (ret != 0) {107perror_exit("pthread_create failed");108}109return thread;110}111112void join_thread(pthread_t thread)113{114int ret = pthread_join(thread, NULL);115if (ret == -1) {116perror_exit("pthread_join failed");117}118}119120// PRODUCER-CONSUMER121122void *producer_entry(void *arg)123{124int i;125Shared *shared = (Shared *) arg;126for (i=0; i<NUM_ITEMS; i++) {127printf("adding item %d\n", i);128queue_push(shared->queue, i);129}130pthread_exit(NULL);131}132133void *consumer_entry(void *arg)134{135int i;136int item;137Shared *shared = (Shared *) arg;138139for (i=0; i<NUM_ITEMS; i++) {140item = queue_pop(shared->queue);141printf("consuming item %d\n", item);142}143pthread_exit(NULL);144}145146// TEST CODE147148void queue_test()149{150int i;151int item;152int length = 128;153154Queue *queue = make_queue(length);155assert(queue_empty(queue));156for (i=0; i<length-1; i++) {157queue_push(queue, i);158}159assert(queue_full(queue));160for (i=0; i<10; i++) {161item = queue_pop(queue);162assert(i == item);163}164assert(!queue_empty(queue));165assert(!queue_full(queue));166for (i=0; i<10; i++) {167queue_push(queue, i);168}169assert(queue_full(queue));170for (i=0; i<10; i++) {171item = queue_pop(queue);172}173assert(item == 19);174}175176int main()177{178int i;179pthread_t child[NUM_CHILDREN];180181Shared *shared = make_shared();182183child[0] = make_thread(producer_entry, shared);184child[1] = make_thread(consumer_entry, shared);185186for (i=0; i<NUM_CHILDREN; i++) {187join_thread(child[i]);188}189190return 0;191}192193194