/* Example code for Think OS. Copyright 2015 Allen Downey License: Creative Commons Attribution-ShareAlike 3.0 */ #include #include #include #include #include "utils.h" #define NUM_CHILDREN 2 #define QUEUE_LENGTH 1600000 #define NUM_ITEMS (QUEUE_LENGTH - 1) // QUEUE typedef struct { int *array; int length; int next_in; int next_out; Mutex *mutex; Cond *nonempty; Cond *nonfull; } Queue; Queue *make_queue(int length) { Queue *queue = (Queue *) malloc(sizeof(Queue)); queue->length = length; queue->array = (int *) malloc(length * sizeof(int)); queue->next_in = 0; queue->next_out = 0; queue->mutex = make_mutex(); queue->nonempty = make_cond(); queue->nonfull = make_cond(); return queue; } int queue_incr(Queue *queue, int i) { return (i+1) % queue->length; } int queue_empty(Queue *queue) { // queue is empty if next_in and next_out are the same int res = (queue->next_in == queue->next_out); return res; } int queue_full(Queue *queue) { // queue is full if incrementing next_in lands on next_out int res = (queue_incr(queue, queue->next_in) == queue->next_out); return res; } void queue_push(Queue *queue, int item) { mutex_lock(queue->mutex); while (queue_full(queue)) { cond_wait(queue->nonfull, queue->mutex); } queue->array[queue->next_in] = item; queue->next_in = queue_incr(queue, queue->next_in); mutex_unlock(queue->mutex); cond_signal(queue->nonempty); } int queue_pop(Queue *queue) { mutex_lock(queue->mutex); while (queue_empty(queue)) { cond_wait(queue->nonempty, queue->mutex); } int item = queue->array[queue->next_out]; queue->next_out = queue_incr(queue, queue->next_out); mutex_unlock(queue->mutex); cond_signal(queue->nonfull); return item; } // SHARED typedef struct { Queue *queue; } Shared; Shared *make_shared() { Shared *shared = check_malloc(sizeof(Shared)); shared->queue = make_queue(QUEUE_LENGTH); return shared; } // THREAD pthread_t make_thread(void *(*entry)(void *), Shared *shared) { int ret; pthread_t thread; ret = pthread_create(&thread, NULL, entry, (void *) shared); if (ret != 0) { perror_exit("pthread_create failed"); } return thread; } void join_thread(pthread_t thread) { int ret = pthread_join(thread, NULL); if (ret == -1) { perror_exit("pthread_join failed"); } } // PRODUCER-CONSUMER void *producer_entry(void *arg) { int i; Shared *shared = (Shared *) arg; for (i=0; iqueue, i); } pthread_exit(NULL); } void *consumer_entry(void *arg) { int i; int item; Shared *shared = (Shared *) arg; for (i=0; iqueue); printf("consuming item %d\n", item); } pthread_exit(NULL); } // TEST CODE #include "testing.ic" int main() { thread_safe_test(); empty_queue_test(); return 0; }