Skip to content

Instantly share code, notes, and snippets.

@fclairamb
Last active December 23, 2015 09:48
Show Gist options
  • Save fclairamb/6616641 to your computer and use it in GitHub Desktop.
Save fclairamb/6616641 to your computer and use it in GitHub Desktop.
Producer/Consumer exercice as requested by superman. v2, superman wasn't happy enough.
#ifdef SHELL
SCENARIO=$1
if [ "${SCENARIO}" = "" ]; then
SCENARIO=1
fi
gcc -pthread -O3 -DSCENARIO=${SCENARIO} -Wall -Werror $0 && ./a.out
exit 0
#endif
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
enum {
PRODUCER,
CONSUMER
};
enum {
OK,
ERR
};
typedef struct {
unsigned char type;
unsigned int pause;
int loops;
char * name;
pthread_t thread;
} thread_parameter_t;
/*******************************************************************************
*** SETUP ***
******************************************************************************/
#define BUFFER_SIZE 10
#define RUNNING_TIME 60000
// This is our setup
thread_parameter_t par_threads[] = {
#ifndef SCENARIO
#define SCENARIO 1
#endif
#if SCENARIO == 1
{ PRODUCER, 2000, RUNNING_TIME / 2000, " producer"},
{ CONSUMER, 3000, RUNNING_TIME / 3000, "consumer(1)"},
{ CONSUMER, 5000, RUNNING_TIME / 5000, "consumer(2)"},
#elif SCENARIO == 2
{ PRODUCER, 0, 0, "producer(1)"},
{ PRODUCER, 0, 0, "producer(2)"},
{ CONSUMER, 0, 0, "consumer(1)"},
{ CONSUMER, 0, 0, "consumer(2)"},
#elif SCENARIO == 3
{ PRODUCER, 0, 80000, "producer(1)"},
{ CONSUMER, 0, 200000, "consumer(1)"},
{ CONSUMER, 0, 200000, "consumer(2)"}
#elif SCENARIO == 4
{ PRODUCER, 500, RUNNING_TIME / 1000, "producer" },
{ CONSUMER, 2000, RUNNING_TIME / 1000, "consumer" },
#elif SCENARIO == 5
{ PRODUCER, 2000, RUNNING_TIME / 1000, "producer" },
{ CONSUMER, 500, RUNNING_TIME / 1000, "consumer" },
#endif
};
typedef struct {
pthread_mutex_t mutex;
int data[BUFFER_SIZE];
uint16_t index_read, index_write;
} buffer_t;
buffer_t buffer = {};
unsigned char buffer_add(int el) {
unsigned char rc = ERR;
pthread_mutex_lock(& buffer.mutex);
if (buffer.index_read <= buffer.index_write && buffer.index_read + BUFFER_SIZE > buffer.index_write) {
buffer.data[buffer.index_write++ % BUFFER_SIZE] = el;
rc = OK;
// This is highly theorical
if (buffer.index_write == UINT16_MAX) {
buffer.index_write = buffer.index_write % BUFFER_SIZE;
buffer.index_read = buffer.index_read % BUFFER_SIZE;
}
}
pthread_mutex_unlock(& buffer.mutex);
return rc;
}
unsigned char buffer_get(int * el) {
unsigned char rc = ERR;
pthread_mutex_lock(& buffer.mutex);
if (buffer.index_read < buffer.index_write) {
*el = buffer.data[buffer.index_read++ % BUFFER_SIZE];
rc = OK;
}
pthread_mutex_unlock(& buffer.mutex);
return rc;
}
void * thread_method(void *ptr) {
thread_parameter_t * par = (thread_parameter_t*) ptr;
int i, c = 0;
for (i = 0; i < par->loops || !par->loops /* loops == 0 for infinite loops */; ++i) {
if (par->type == PRODUCER) {
if (buffer_add(c) == OK) {
printf("[%s] --> %d\n", par->name, c++);
} else {
printf("[%s] --\n", par->name);
}
} else {
if (buffer_get(&c) == OK) {
printf("[%s] <-- %d\n", par->name, c);
} else {
printf("[%s] --\n", par->name);
}
}
usleep(par->pause * 1000);
}
printf("[%s] end\n", par->name);
return NULL;
}
int main() {
printf("=====================\n");
printf("Started SCENARIO %d...\n", SCENARIO);
printf("=====================\n");
unsigned int i;
for (i = 0; i < ARRAY_SIZE(par_threads); i++) {
thread_parameter_t * par = &par_threads[i];
pthread_create(& par->thread, NULL, thread_method, par);
}
printf("STARTED !\n");
for (i = 0; i < ARRAY_SIZE(par_threads); i++) {
thread_parameter_t * par = &par_threads[i];
pthread_join(par->thread, NULL);
}
printf("END !\n");
return OK;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment