From 5e7623d831bee52f90265f8fe1be4413a2dda253 Mon Sep 17 00:00:00 2001 From: Rui Ribeiro <42305006+ruiribeiro04@users.noreply.github.com> Date: Tue, 7 Oct 2025 22:22:41 +0100 Subject: [PATCH] Add producer-consumer exercice boilerplate implementation with threading support --- rendu/producer_consumer.c | 136 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 rendu/producer_consumer.c diff --git a/rendu/producer_consumer.c b/rendu/producer_consumer.c new file mode 100644 index 0000000..1a94683 --- /dev/null +++ b/rendu/producer_consumer.c @@ -0,0 +1,136 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* producer_consumer.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: ruiferna +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/10/07 22:17:29 by ruiferna #+# #+# */ +/* Updated: 2025/10/07 22:22:14 by ruiferna ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include // Para memset +#include +#include // Para usleep e write +#include // Para gettimeofday + +#define BUFFER_SIZE 10 +#define NUM_PRODUCERS 2 +#define NUM_CONSUMERS 2 +#define ITEMS_TO_PRODUCE 100 + +/** + * @brief Estrutura de dados partilhada entre as threads. + * + * @param buffer O buffer partilhado (array de inteiros). + * @param in Índice onde o próximo produtor irá escrever. + * @param out Índice de onde o próximo consumidor irá ler. + * @param count Número de itens atualmente no buffer. + * @param items_produced Contador total de itens produzidos para controlo de fim. + * @param mutex Mutex para garantir acesso exclusivo e atómico às + * variáveis desta estrutura. + */ +typedef struct { + int buffer[BUFFER_SIZE]; + int in; + int out; + int count; + int items_produced; + + pthread_mutex_t mutex; +} shared_buffer_t; + +// Protótipos das funções das threads +void *producer_thread(void *arg); +void *consumer_thread(void *arg); + +int main(void) +{ + // 1. Inicializar a estrutura partilhada + shared_buffer_t shared_data; + pthread_t producer_threads[NUM_PRODUCERS]; + pthread_t consumer_threads[NUM_CONSUMERS]; + + // Limpar e inicializar os dados + memset(&shared_data, 0, sizeof(shared_buffer_t)); + + // Inicializar o mutex (função permitida) + if (pthread_mutex_init(&shared_data.mutex, NULL) != 0) { + printf("Erro a inicializar o mutex\\n"); + return 1; + } + + printf("A iniciar threads...\n"); + + // 2. Criar as threads produtoras e consumidoras (função permitida) + for (int i = 0; i < NUM_PRODUCERS; i++) { + if (pthread_create(&producer_threads[i], NULL, producer_thread, &shared_data) != 0) { + printf("Erro a criar thread produtora\\n"); + return 1; + } + } + for (int i = 0; i < NUM_CONSUMERS; i++) { + if (pthread_create(&consumer_threads[i], NULL, consumer_thread, &shared_data) != 0) { + printf("Erro a criar thread consumidora\\n"); + return 1; + } + } + + // 3. Esperar que as threads produtoras terminem (função permitida) + for (int i = 0; i < NUM_PRODUCERS; i++) { + pthread_join(producer_threads[i], NULL); + } + + printf("Produtores terminaram. A aguardar consumidores...\n"); + + // 4. Esperar que as threads consumidoras terminem + // A lógica dentro da thread consumidora deve garantir que ela termina + // quando não há mais itens a serem produzidos e o buffer está vazio. + for (int i = 0; i < NUM_CONSUMERS; i++) { + pthread_join(consumer_threads[i], NULL); + } + + // 5. Destruir o mutex (função permitida) + pthread_mutex_destroy(&shared_data.mutex); + + printf("Programa terminado.\n"); + + return (0); +} + +// Lógica da Thread Produtora (a ser implementada) +void *producer_thread(void *arg) +{ + shared_buffer_t *shared = (shared_buffer_t *)arg; + + // TODO: Implementar a lógica de produção aqui. + // Lembre-se do ciclo: + // 1. Lock mutex. + // 2. WHILE buffer está cheio: unlock, usleep, lock de novo. + // 3. Produzir item. + // 4. Unlock mutex. + + printf("Thread produtora a terminar.\n"); + + return (NULL); +} + +// Lógica da Thread Consumidora (a ser implementada) +void *consumer_thread(void *arg) +{ + shared_buffer_t *shared = (shared_buffer_t *)arg; + + // TODO: Implementar a lógica de consumo aqui. + // Lembre-se do ciclo: + // 1. Lock mutex. + // 2. WHILE buffer está vazio (e ainda há itens a produzir): unlock, usleep, lock de novo. + // 3. Consumir item. + // 4. Unlock mutex. + + printf("Thread consumidora a terminar.\n"); + + return (NULL); +}