#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

#define n 5

int b[n];
int in = 0;
int out = 0;

pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t In_CV = PTHREAD_COND_INITIALIZER;  // Signal for "items available"
pthread_cond_t Out_CV = PTHREAD_COND_INITIALIZER; // Signal for "space available"

void* producer(void* arg) {
    int v = 100; // Ξεκινάμε από το 100 για διάκριση
    while (true) {
        pthread_mutex_lock(&M);
        
        while ((in + 1) % n == out)
            pthread_cond_wait(&Out_CV, &M); // Αναμονή για χώρο
            
        b[in] = v;
        printf("Produced: %d at index %d\n", v, in);
        in = (in + 1) % n;
        v++;
        
        pthread_cond_signal(&In_CV); // Ειδοποίηση καταναλωτή
        pthread_mutex_unlock(&M);
        usleep(100000);
    }
    return NULL;
}

void* consumer(void* arg) {
    int w;
    while (true) {
        pthread_mutex_lock(&M);
        
        while (in == out)
            pthread_cond_wait(&In_CV, &M); // Αναμονή για δεδομένα
            
        w = b[out];
        printf("Consumed: %d from index %d\n", w, out);
        out = (out + 1) % n;
        
        pthread_cond_signal(&Out_CV); // Ειδοποίηση παραγωγού
        pthread_mutex_unlock(&M);
        usleep(300000);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;
    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);
    
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    
    pthread_mutex_destroy(&M);
    pthread_cond_destroy(&In_CV);
    pthread_cond_destroy(&Out_CV);
    return 0;
}
