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

#define n 5 // Μέγεθος του buffer

int b[n];
int in = 0;
int out = 0;
pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;

void* producer(void* arg) {
    int v = 0;
    while (true) {
        /* Παραγωγή αντικειμένου v */
        
        // Busy waiting με Mutex: Το νήμα κλειδώνει/ξεκλειδώνει συνεχώς
        // όσο ο buffer είναι γεμάτος, καταναλώνοντας 100% CPU.
        while (true) {
            pthread_mutex_lock(&M);
            if ((in + 1) % n == out) {
                pthread_mutex_unlock(&M);
            } else {
                // Υπάρχει χώρος, βγαίνουμε από το loop με το lock κρατημένο
                break;
            }
        }

        b[in] = v;
        printf("Παραγωγή: %d\n", v);
        v++;
        in = (in + 1) % n;

        pthread_mutex_unlock(&M);
        usleep(100000); 
    }
    return NULL;
}

void* consumer(void* arg) {
    int w;
    while (true) {
        // Busy waiting με Mutex: Το νήμα "καίει" κύκλους CPU 
        // ελέγχοντας αν ο buffer είναι άδειος (in == out).
        while (true) {
            pthread_mutex_lock(&M);
            if (in == out) {
                pthread_mutex_unlock(&M);
            } else {
                // Υπάρχουν δεδομένα, βγαίνουμε από το loop με το lock κρατημένο
                break;
            }
        }

        w = b[out];
        printf("Κατανάλωση: %d\n", w);
        out = (out + 1) % n;

        pthread_mutex_unlock(&M);
        usleep(300000);
    }
    return NULL;
}

int main() {
    pthread_t prod, cons;
    
    printf("Εκκίνηση: Buffer με Mutex και Busy Waiting (in == out)...\n");

    pthread_create(&prod, NULL, producer, NULL);
    pthread_create(&cons, NULL, consumer, NULL);
    
    pthread_join(prod, NULL);
    pthread_join(cons, NULL);
    
    pthread_mutex_destroy(&M);
    return 0;
}
