📚 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 <semaphore.h>12#include "utils.h"13#include "mysem.h"1415#define NUM_CHILDREN 216#define NUM_ITEMS 1271718// QUEUE1920typedef struct {21int *array;22int length;23int next_in;24int next_out;25Semaphore *mutex;26Semaphore *items;27Semaphore *spaces;28} Queue;2930Queue *make_queue(int length)31{32Queue *queue = (Queue *) malloc(sizeof(Queue));33queue->length = length;34queue->array = (int *) malloc(length * sizeof(int));35queue->next_in = 0;36queue->next_out = 0;37queue->mutex = make_semaphore(1);38queue->items = make_semaphore(0);39queue->spaces = make_semaphore(length);40return queue;41}4243int queue_incr(Queue *queue, int i)44{45return (i+1) % queue->length;46}4748int queue_empty(Queue *queue)49{50// queue is empty if next_in and next_out are the same51int res = (queue->next_in == queue->next_out);52return res;53}5455int queue_full(Queue *queue)56{57// queue is full if incrementing next_in lands on next_out58int res = (queue_incr(queue, queue->next_in) == queue->next_out);59return res;60}6162void queue_push(Queue *queue, int item) {63semaphore_wait(queue->spaces);64semaphore_wait(queue->mutex);6566queue->array[queue->next_in] = item;67queue->next_in = queue_incr(queue, queue->next_in);6869semaphore_signal(queue->mutex);70semaphore_signal(queue->items);71}7273int queue_pop(Queue *queue) {74semaphore_wait(queue->items);75semaphore_wait(queue->mutex);7677int item = queue->array[queue->next_out];78queue->next_out = queue_incr(queue, queue->next_out);7980semaphore_signal(queue->mutex);81semaphore_signal(queue->spaces);8283return item;84}8586// SHARED8788typedef struct {89Queue *queue;90} Shared;9192Shared *make_shared()93{94Shared *shared = check_malloc(sizeof(Shared));95shared->queue = make_queue(128);96return shared;97}9899// THREAD100101pthread_t make_thread(void *(*entry)(void *), Shared *shared)102{103int ret;104pthread_t thread;105106ret = pthread_create(&thread, NULL, entry, (void *) shared);107if (ret != 0) {108perror_exit("pthread_create failed");109}110return thread;111}112113void join_thread(pthread_t thread)114{115int ret = pthread_join(thread, NULL);116if (ret == -1) {117perror_exit("pthread_join failed");118}119}120121// PRODUCER-CONSUMER122123void *producer_entry(void *arg)124{125int i;126Shared *shared = (Shared *) arg;127for (i=0; i<NUM_ITEMS; i++) {128printf("adding item %d\n", i);129queue_push(shared->queue, i);130}131pthread_exit(NULL);132}133134void *consumer_entry(void *arg)135{136int i;137int item;138Shared *shared = (Shared *) arg;139140for (i=0; i<NUM_ITEMS; i++) {141item = queue_pop(shared->queue);142printf("consuming item %d\n", item);143}144pthread_exit(NULL);145}146147// TEST CODE148149void queue_test()150{151int i;152int item;153int length = 128;154155Queue *queue = make_queue(length);156assert(queue_empty(queue));157for (i=0; i<length-1; i++) {158queue_push(queue, i);159}160assert(queue_full(queue));161for (i=0; i<10; i++) {162item = queue_pop(queue);163assert(i == item);164}165assert(!queue_empty(queue));166assert(!queue_full(queue));167for (i=0; i<10; i++) {168queue_push(queue, i);169}170assert(queue_full(queue));171for (i=0; i<10; i++) {172item = queue_pop(queue);173}174assert(item == 19);175}176177int main()178{179int i;180pthread_t child[NUM_CHILDREN];181182Shared *shared = make_shared();183184child[0] = make_thread(producer_entry, shared);185child[1] = make_thread(consumer_entry, shared);186187for (i=0; i<NUM_CHILDREN; i++) {188join_thread(child[i]);189}190191return 0;192}193194195