Last active
January 5, 2023 17:42
-
-
Save jachermocilla/a7ab7c3992799d2b167aa3eb22d053d1 to your computer and use it in GitHub Desktop.
Producer-Consumer Problem Solutions (compile with -lpthread)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE //to be able to use pthread_setname_np() | |
//implementation of solution to prod-con from chapter 3, dino book | |
//not all slots are used | |
//-jach | |
// | |
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#define BUFFER_SIZE 5 | |
#define NITER 10 | |
//Function prototypes | |
void *producer(); | |
void *consumer(); | |
//Shared by the producer and consumer thread | |
int buffer[BUFFER_SIZE]; | |
int in = 0; //next free position | |
int out = 0; //first full position | |
int main(){ | |
pthread_t prod_thread, con_thread; | |
srand(time(NULL)); | |
pthread_create (&prod_thread, NULL, producer, NULL); | |
pthread_create (&con_thread, NULL, consumer, NULL); | |
pthread_setname_np(prod_thread, "ProducerThread"); | |
pthread_setname_np(con_thread, "ConsumerThread"); | |
pthread_join(prod_thread, NULL); | |
pthread_join(con_thread, NULL); | |
return 0; | |
} | |
void *producer(){ | |
int next_produced; | |
//while (1){ | |
for (int i=0; i< NITER; i++) { | |
/* produce an item in next produced */ | |
next_produced=rand() % 100 + 1; | |
//Do nothing until a slot is available | |
while (((in + 1) % BUFFER_SIZE) == out) | |
; | |
buffer[in] = next_produced; | |
printf("Producer produced [%d].(Placed in index:in=%d,out=%d)\n",next_produced,in,out); | |
in = (in + 1) % BUFFER_SIZE; | |
} | |
} | |
void *consumer(){ | |
int next_consumed; | |
//while(1){ | |
for (int i=0; i< NITER; i++) { | |
//Do nothing if the buffer is empty | |
while (in == out) | |
; | |
next_consumed = buffer[out]; | |
printf("\t\tConsumer consumed [%d].(in=%d,Consumed from index: out=%d)\n",next_consumed,in,out); | |
out = (out + 1) % BUFFER_SIZE; | |
/* consume the item in next consumed */ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <time.h> | |
// | |
//solution to prod-con problem using a counter to be able to use | |
//all slots in the buffer. it uses condition variables. | |
//-jach | |
// | |
#define BUFFER_SIZE 5 | |
#define NITER 15 | |
//Function prototypes | |
void *producer(); | |
void *consumer(); | |
//Shared by the producer and consumer thread | |
int buffer[BUFFER_SIZE]; | |
int in = 0; //next free position | |
int out = 0; //first full position | |
//Counter to hold the total number of elements | |
//We use this in order to fill all slots. | |
int counter=0; | |
pthread_mutex_t mutex; //for mutual exclusion | |
pthread_cond_t item_available; //event that an item is available | |
pthread_cond_t slot_available; //event that a slot is available | |
int main(){ | |
pthread_t prod_thread, con_thread; | |
srand(time(NULL)); | |
pthread_mutex_init(&mutex,NULL); //initialize mutex and condition variables | |
pthread_cond_init(&item_available, NULL); | |
pthread_create (&prod_thread, NULL, producer, NULL); | |
pthread_create (&con_thread, NULL, consumer, NULL); | |
pthread_join(prod_thread, NULL); | |
pthread_join(con_thread, NULL); | |
printf("Counter: %d\n",counter); | |
return 0; | |
} | |
void *producer(){ | |
int next_produced; | |
//while (1){ | |
for (int i=0; i< NITER; i++) { | |
/* produce an item in next produced */ | |
next_produced=rand() % 100 + 1; | |
pthread_mutex_lock(&mutex); | |
while (counter==BUFFER_SIZE) | |
pthread_cond_wait(&slot_available, &mutex); //wait for an event that a slot is available | |
buffer[in] = next_produced; | |
printf("Producer produced [%d].(Placed in index:in=%d,out=%d)\n",next_produced,in,out); | |
in = (in + 1) % BUFFER_SIZE; | |
counter++; | |
pthread_cond_signal(&item_available); //signal that an item is available | |
pthread_mutex_unlock(&mutex); | |
} | |
} | |
void *consumer(){ | |
int next_consumed; | |
//while(1){ | |
for (int i=0; i< NITER; i++) { | |
pthread_mutex_lock(&mutex); | |
while (counter==0) | |
pthread_cond_wait(&item_available, &mutex); //wait for an event that an item is available | |
next_consumed = buffer[out]; | |
printf("\t\tConsumer consumed [%d].(in=%d,Consumed from index: out=%d)\n",next_consumed,in,out); | |
out = (out + 1) % BUFFER_SIZE; | |
counter--; | |
pthread_cond_signal(&slot_available); //signal that a slot is available | |
pthread_mutex_unlock(&mutex); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//OMP implementation of solution to prod-con from chapter 3, dino book | |
//not all slots are used | |
//-jach | |
// | |
// $ gcc -o prodcon_omp.exe prodcon_omp.c -fopenmp | |
// | |
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#define BUFFER_SIZE 5 | |
#define NITER 10 | |
//Function prototypes | |
void *producer(); | |
void *consumer(); | |
//Shared by the producer and consumer thread | |
int buffer[BUFFER_SIZE]; | |
int in = 0; //next free position | |
int out = 0; //first full position | |
int main(){ | |
srand(time(NULL)); | |
#pragma omp parallel sections | |
{ | |
#pragma omp section | |
producer(); | |
#pragma omp section | |
consumer(); | |
} | |
return 0; | |
} | |
void *producer(){ | |
int next_produced; | |
//while (1){ | |
for (int i=0; i< NITER; i++) { | |
next_produced=rand() % 100 + 1; | |
//Do nothing until a slot is available | |
while (((in + 1) % BUFFER_SIZE) == out) | |
; | |
buffer[in] = next_produced; | |
printf("Producer produced [%d].(Placed in index:in=%d,out=%d)\n",next_produced,in,out); | |
in = (in + 1) % BUFFER_SIZE; | |
} | |
} | |
void *consumer(){ | |
int next_consumed; | |
//while(1){ | |
for (int i=0; i< NITER; i++) { | |
//Do nothing if the buffer is empty | |
while (in == out) | |
; | |
next_consumed = buffer[out]; | |
printf("\t\tConsumer consumed [%d].(in=%d,Consumed from index: out=%d)\n",next_consumed,in,out); | |
out = (out + 1) % BUFFER_SIZE; | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <time.h> | |
// | |
//solution to prod-con problem using a counter to be able to use | |
//all slots in the buffer. Suffers from race condition | |
//-jach | |
// | |
#define BUFFER_SIZE 5 | |
#define NITER 1000 | |
//Function prototypes | |
void *producer(); | |
void *consumer(); | |
//Shared by the producer and consumer thread | |
int buffer[BUFFER_SIZE]; | |
int in = 0; //next free position | |
int out = 0; //first full position | |
//Counter to hold the total number of elements | |
//We use this in order to fill all slots. | |
int counter=0; | |
int main(){ | |
pthread_t prod_thread, con_thread; | |
srand(time(NULL)); | |
pthread_create (&prod_thread, NULL, producer, NULL); | |
pthread_create (&con_thread, NULL, consumer, NULL); | |
pthread_join(prod_thread, NULL); | |
pthread_join(con_thread, NULL); | |
printf("Counter: %d\n",counter); | |
return 0; | |
} | |
void *producer(){ | |
int next_produced; | |
//while (1){ | |
for (int i=0; i< NITER; i++) { | |
/* produce an item in next produced */ | |
next_produced=rand() % 100 + 1; | |
//Do nothing when the buffer is full | |
while (counter==BUFFER_SIZE) | |
; | |
buffer[in] = next_produced; | |
//printf("Producer produced [%d].(Placed in index:in=%d,out=%d)\n",next_produced,in,out); | |
in = (in + 1) % BUFFER_SIZE; | |
counter++; | |
} | |
} | |
void *consumer(){ | |
int next_consumed; | |
//while(1){ | |
for (int i=0; i< NITER; i++) { | |
//Do nothing until an item is available | |
while (counter==0) | |
; | |
next_consumed = buffer[out]; | |
//printf("\t\tConsumer consumed [%d].(in=%d,Consumed from index: out=%d)\n",next_consumed,in,out); | |
out = (out + 1) % BUFFER_SIZE; | |
counter--; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <semaphore.h> | |
// | |
// implementation of solution to prod-con using | |
// semaphores. | |
// -jach | |
// | |
// | |
//The number of elements in the buffer | |
#define BUFFER_SIZE 5 | |
//Number of producer threads | |
#define NPROD 1 | |
//Number of consumer threads | |
#define NCON 1 | |
//Number of iterations in the producer | |
#define PRODITER 20 | |
//Number of iterations in the consumer | |
#define CONITER 20 | |
//Function prototypes | |
void *producer(void *); | |
void *consumer(void *); | |
//Shared data by the producer and consumer thread | |
//------------------------------------------------ | |
int buffer[BUFFER_SIZE]; | |
int in = 0; //next free position | |
int out = 0; //first full position | |
sem_t mutex; //semaphore to lock buffer | |
sem_t full; //counts the number of filled slots | |
sem_t empty; //counts the number of empty slots | |
//------------------------------------------------ | |
int main(){ | |
//Array if thread ids for producer | |
pthread_t prod_thread[NPROD]; | |
//Array of thread ids for consumer | |
pthread_t con_thread[NCON]; | |
int i,j; | |
//Placeholder of parameters passed to the thread, the id | |
int *prod_id,*con_id; | |
//Initialize the random number generator | |
srand(time(NULL)); | |
sem_init(&mutex,0,1); //we lock the buffer | |
sem_init(&full,0,0); //no items yet | |
sem_init(&empty,0,BUFFER_SIZE); //all buffers are empty | |
for (i=0;i<NPROD;i++){ | |
prod_id=(int *)malloc(sizeof(int)); | |
*prod_id=i; | |
pthread_create (&prod_thread[0], NULL, producer, prod_id); | |
} | |
for (j=0;j<NCON;j++){ | |
con_id=(int *)malloc(sizeof(int)); | |
*con_id=j; | |
pthread_create (&con_thread[0], NULL, consumer, con_id); | |
} | |
for (i=0;i<NPROD;i++){ | |
pthread_join(prod_thread[i], NULL); | |
} | |
for (j=0;j<NCON;j++){ | |
pthread_join(con_thread[j], NULL); | |
} | |
return 0; | |
} | |
void *producer(void *i){ | |
int next_produced; | |
int prod_id=*((int *)i); | |
int full_val,empty_val; | |
//while (1){ | |
for (int i=0; i< PRODITER; i++) { | |
/* produce an item in next produced by generating a random number*/ | |
next_produced=rand() % 100 + 1; | |
sem_wait(&empty); //wait for an empty slot | |
sem_wait(&mutex); //wait for lock to access shared data:buffer, in | |
//critical section | |
buffer[in] = next_produced; | |
printf("Producer %d produced [%d].(Placed in index: in=%d,out=%d,),", | |
prod_id, next_produced,in,out); | |
in = (in + 1) % BUFFER_SIZE; | |
sem_post(&mutex); //release the lock on the shared data | |
sem_post(&full); //signal that an item is available | |
//get the value of the semaphores | |
sem_getvalue(&empty,&empty_val); | |
sem_getvalue(&full,&full_val); | |
printf("semaphores: empty=%d,full=%d\n",empty_val,full_val); | |
} | |
} | |
void *consumer(void *i){ | |
int next_consumed; | |
int con_id=*((int *)i); | |
int full_val,empty_val; | |
//while(1){ | |
for (int i=0; i< CONITER; i++) { | |
sem_wait(&full); //wait for an item to be available | |
sem_wait(&mutex); //wait for the lock to access shared data: buffer, out | |
//critical section | |
next_consumed = buffer[out]; | |
//get the value of the semaphores | |
sem_getvalue(&empty,&empty_val); | |
sem_getvalue(&full,&full_val); | |
printf("\t\tConsumer %d consumed [%d].(in=%d,Consumed from: out=%d),", | |
con_id,next_consumed,in,out); | |
out = (out + 1) % BUFFER_SIZE; | |
sem_post(&mutex); //release the lock on the shared data | |
sem_post(&empty); //signal that a new item has been consumed | |
//get the value of the semaphores | |
sem_getvalue(&empty,&empty_val); | |
sem_getvalue(&full,&full_val); | |
printf("semaphores: empty=%d,full=%d\n",empty_val,full_val); | |
/* consume the item in next consumed */ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment