From d532b42edac5e0bef96c8e6f974feff69cfbfe42 Mon Sep 17 00:00:00 2001 From: "Remzi H. Arpaci-Dusseau" Date: Mon, 22 Apr 2019 10:51:36 -0500 Subject: [PATCH] producer/consumer code (working) --- threads-sema/Makefile | 1 + threads-sema/README.md | 19 +++++ threads-sema/producer_consumer_works.c | 107 +++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 threads-sema/producer_consumer_works.c diff --git a/threads-sema/Makefile b/threads-sema/Makefile index 071cf1f..32c63fa 100644 --- a/threads-sema/Makefile +++ b/threads-sema/Makefile @@ -7,6 +7,7 @@ SRCS := dining_philosophers_deadlock.c \ dining_philosophers_no_deadlock_print.c \ join.c \ binary.c \ + producer_consumer_works.c \ zemaphore.c OBJS := ${SRCS:c=o} diff --git a/threads-sema/README.md b/threads-sema/README.md index 0fa6c3e..9683b9c 100644 --- a/threads-sema/README.md +++ b/threads-sema/README.md @@ -24,6 +24,25 @@ prompt> make prompt> ./binary ``` +# Producer/Consumer + +Code for the working producer/consumer solution from the text, +found in `producer_consumer.c`. + +Run `make` to build, and `producer_consumer` to test it. +The program takes a few different arguments: +- The number of buffers between the producer/consumer +- The number of times a producer should produce something +- The number of consumer threads + +```sh +prompt> make +prompt> ./producer_consumer 1 1000 1 +``` + +The output should print each produced item once, and show which +consumer consumed each produced item. + # Dining Philosophers diff --git a/threads-sema/producer_consumer_works.c b/threads-sema/producer_consumer_works.c new file mode 100644 index 0000000..798ade0 --- /dev/null +++ b/threads-sema/producer_consumer_works.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "common_threads.h" + +int max; +int loops; +int *buffer; + +int use = 0; +int fill = 0; + +sem_t empty; +sem_t full; +sem_t mutex; + +#define CMAX (10) +int consumers = 1; + +void do_fill(int value) { + buffer[fill] = value; + fill++; + if (fill == max) + fill = 0; +} + +int do_get() { + int tmp = buffer[use]; + use++; + if (use == max) + use = 0; + return tmp; +} + +void *producer(void *arg) { + int i; + for (i = 0; i < loops; i++) { + Sem_wait(&empty); + Sem_wait(&mutex); + do_fill(i); + Sem_post(&mutex); + Sem_post(&full); + } + + // end case + for (i = 0; i < consumers; i++) { + Sem_wait(&empty); + Sem_wait(&mutex); + do_fill(-1); + Sem_post(&mutex); + Sem_post(&full); + } + + return NULL; +} + +void *consumer(void *arg) { + int tmp = 0; + while (tmp != -1) { + Sem_wait(&full); + Sem_wait(&mutex); + tmp = do_get(); + Sem_post(&mutex); + Sem_post(&empty); + printf("%lld %d\n", (long long int) arg, tmp); + } + return NULL; +} + +int main(int argc, char *argv[]) { + if (argc != 4) { + fprintf(stderr, "usage: %s \n", argv[0]); + exit(1); + } + max = atoi(argv[1]); + loops = atoi(argv[2]); + consumers = atoi(argv[3]); + assert(consumers <= CMAX); + + buffer = (int *) malloc(max * sizeof(int)); + assert(buffer != NULL); + int i; + for (i = 0; i < max; i++) { + buffer[i] = 0; + } + + Sem_init(&empty, max); // max are empty + Sem_init(&full, 0); // 0 are full + Sem_init(&mutex, 1); // mutex + + pthread_t pid, cid[CMAX]; + Pthread_create(&pid, NULL, producer, NULL); + for (i = 0; i < consumers; i++) { + Pthread_create(&cid[i], NULL, consumer, (void *) (long long int) i); + } + Pthread_join(pid, NULL); + for (i = 0; i < consumers; i++) { + Pthread_join(cid[i], NULL); + } + return 0; +} +