I am trying to create a consumer-producer program where the consumer thread producer numbers to fill an array, and a consumer thread prints the numbers that populate the array. Currently, I can fill the array and pass data back and forth between the consumer/producer threads, but I want the producer to create numbers faster than the consumer processes them.
At the moment, a number is produced every 1 second, and a number is consumed every 3. Two numbers should be produced before one is consumed, but my producer thread is waiting until the number it produced is consumed.
I've tried moving around the mutex locks and unlocks, and also the signals, but I haven't gotten it to work. The following code produces the following output:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
struct Data {
int num;
int wait_time;
};
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
//int count = 0;
struct Data buffer[32];
void* producer(void *ptr) {
int i, w; /* counter and random wait time */
struct Data data;
int count = 0;
while(1) {
//w = rand() % 5 + 3;
w = 1;
sleep(w); /* Wait between 3 and 7 seconds */
data.num = rand() % 1000; /* Create random number to pass */
//data.wait_time = rand() % 8 + 2;
data.wait_time = 3;
pthread_mutex_lock(&the_mutex); /* lock the buffer */
while (buffer[count].num != 0) { /* while full */
//pthread_cond_signal(&condc);
pthread_cond_wait(&condp, &the_mutex);
}
//pthread_mutex_lock(&the_mutex); /* lock the buffer */
buffer[count] = data;
pthread_cond_signal(&condc); /* signal consumer */
pthread_mutex_unlock(&the_mutex);
printf("Produced %i and slept for %i seconds\n", buffer[count].num, w);
if (count != 31){
count += 1;
//printf("Producer count: %i\n", count);
}
else
count = 0;
//pthread_cond_signal(&condc); /* signal consumer */
//pthread_mutex_unlock(&the_mutex); /* unlock */
}
pthread_exit(0);
}
void* consumer(void *ptr) {
int i;
int count = 0;
//for(i = 1; i <= MAX; i++) {
while(1) {
pthread_mutex_lock(&the_mutex); /* lock th buffer */
while(buffer[count].num == 0){
//pthread_cond_signal(&condp); /* while empty */
pthread_cond_wait(&condc, &the_mutex);
}
//pthread_mutex_lock(&the_mutex);
sleep(buffer[count].wait_time);
printf("Consumed %i and slept for %i seconds\n", buffer[count].num, buffer[count].wait_time);
//pthread_mutex_lock(&the_mutex);
buffer[count].num = 0;
buffer[count].wait_time = 0;
pthread_cond_signal(&condp); /* signal producer */
pthread_mutex_unlock(&the_mutex);
if(count != 31){
count += 1;
//printf("Consumer count: %i\n", count);
}
else
count = 0;
//pthread_cond_signal(&condp); /* signal producer */
//pthread_mutex_unlock(&the_mutex); /* unlock */
}
pthread_exit(0);
}
int main(int argc, char **argv) {
pthread_t pro, con;
srand(time(NULL));
for (int i = 0; i < 32; i++) { /* Initialize buffer */
buffer[i].num = 0;
buffer[i].wait_time = 0;
}
// Initialize the mutex and condition variables
/* What's the NULL for ??? */
pthread_mutex_init(&the_mutex, NULL);
pthread_cond_init(&condc, NULL); /* Initialize consumer condition variable */
pthread_cond_init(&condp, NULL); /* Initialize producer condition variable */
// Create the threads
pthread_create(&con, NULL, consumer, NULL);
pthread_create(&pro, NULL, producer, NULL);
// Wait for the threads to finish
// Otherwise main might run to the end
// and kill the entire process when it exits.
pthread_join(con, NULL);
pthread_join(pro, NULL);
//pthread_join(&con, NULL);
//pthread_join(&pro, NULL);
// Cleanup -- would happen automatically at end of program
pthread_mutex_destroy(&the_mutex); /* Free up the_mutex */
pthread_cond_destroy(&condc); /* Free up consumer condition variable */
pthread_cond_destroy(&condp); /* Free up producer condition variable */
}
Output (The program prints the 1st line after 1 seconds, then prints both the 2nd and 3rd at the same time after 3 seconds):
Produced 985 and slept for 1 seconds
Consumed 985 and slept for 3 seconds
Produced 540 and slept for 1 seconds
I would rather have the output look something like this:
Produced 985 and slept for 1 seconds
Produced 540 and slept for 1 seconds
Consumed 985 and slept for 3 seconds
The consumer is locking the mutex then sleeping for 3 seconds. So the producer is having to wait for the consumer to finish it's job/sleep before it can produce something else. Avoid sleeping either thread when a lock is in place.
EDIT: Just edited your code a bit and this seems to work without the signals etc here. Give it a go:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
struct Data {
int num;
int wait_time;
};
pthread_mutex_t the_mutex;
pthread_cond_t condc, condp;
struct Data buffer[32];
void* producer(void *ptr) {
int i, w; /* counter and random wait time */
struct Data data;
int count = 0;
while(1) {
printf("prod count %d\n",count);
w = 1;
sleep(w);
data.num = rand() % 1000;
data.wait_time = 3;
while (buffer[count].num != 0) {
printf("buffer full, count = %d\n", count);
sleep(1);
}
// Only using the mutex when we want to change the variable.
pthread_mutex_lock(&the_mutex);
buffer[count] = data;
pthread_mutex_unlock(&the_mutex);
printf("Produced %i and slept for %i seconds\n", buffer[count].num, w);
if (count != 31){
count += 1;
}
else
count = 0;
}
pthread_exit(0);
}
void* consumer(void *ptr) {
int i;
int count = 0;
while(1) { /* lock th buffer */
printf("cons count %d\n",count);
while(buffer[count].num == 0){
printf("buffer empty, count = %d\n", count);
sleep(1);
}
sleep(buffer[count].wait_time);
printf("Consumed %i and slept for %i seconds\n", buffer[count].num, buffer[count].wait_time);
pthread_mutex_lock(&the_mutex);
buffer[count].num = 0;
buffer[count].wait_time = 0;
pthread_mutex_unlock(&the_mutex);
if(count != 31){
count += 1;
//printf("Consumer count: %i\n", count);
}
else {
count = 0;
}
}
pthread_exit(0);
}
int main(int argc, char **argv) {
pthread_t pro, con;
srand(time(NULL));
for (int i = 0; i < 32; i++) { /* Initialize buffer */
buffer[i].num = 0;
buffer[i].wait_time = 0;
}
// Initialize the mutex and condition variables
/* What's the NULL for ??? */
pthread_mutex_init(&the_mutex, NULL);
pthread_cond_init(&condc, NULL); /* Initialize consumer condition variable */
pthread_cond_init(&condp, NULL); /* Initialize producer condition variable */
// Create the threads
pthread_create(&con, NULL, consumer, NULL);
pthread_create(&pro, NULL, producer, NULL);
// Wait for the threads to finish
// Otherwise main might run to the end
// and kill the entire process when it exits.
pthread_join(con, NULL);
pthread_join(pro, NULL);
//pthread_join(&con, NULL);
//pthread_join(&pro, NULL);
// Cleanup -- would happen automatically at end of program
pthread_mutex_destroy(&the_mutex); /* Free up the_mutex */
pthread_cond_destroy(&condc); /* Free up consumer condition variable */
pthread_cond_destroy(&condp); /* Free up producer condition variable */
}