/** * ============================================================================ * PHM Open Source — Sistemas Operacionais & Concorrência * Algoritmo 01: Problema do Produtor-Consumidor com Semáforos e POSIX Threads * Autor: Prof. Paulo Henrique Maciel · PHM Tech * ============================================================================ * * CONCEITO TEÓRICO DE S.O.: * O problema do Produtor-Consumidor (Bounded-Buffer Problem) é um clássico * paradigma de sincronização concorrente. Múltiplas threads compartilham um * buffer de tamanho limitado. O produtor insere itens e o consumidor retira itens. * * DESAFIOS RESOLVIDOS: * 1. Exclusão Mútua (Mutex): Garantir que apenas uma thread acesse o buffer por vez. * 2. Condição de Corrida (Race Condition): Prevenida pelo mutex. * 3. Sincronização por Semáforos: * - sem_vazio: Conta quantos espaços livres restam no buffer. * - sem_cheio: Conta quantos itens prontos para consumo existem. * * COMO COMPILAR E EXECUTAR: * gcc 01_semaforos_produtor_consumidor.c -o so_semaforos -pthread && ./so_semaforos * ============================================================================ */ #include #include #include #include #include #define TAM_BUFFER 5 // Capacidade máxima do buffer compartilhado #define TOTAL_ITENS 10 // Total de itens produzidos/consumidos nesta simulação // Buffer compartilhado circular int buffer[TAM_BUFFER]; int indiceProducao = 0; int indiceConsumo = 0; // Primitivas de sincronização do Sistema Operacional pthread_mutex_t mutexBuffer; // Protege a seção crítica (buffer) sem_t semVazio; // Controla espaços vazios disponíveis sem_t semCheio; // Controla itens disponíveis para consumo // Thread Produtora void* funcaoProdutor(void *arg) { for (int i = 1; i <= TOTAL_ITENS; i++) { // Simula tempo de produção usleep(150000); // 150ms // Aguarda haver ao menos 1 espaço vazio no buffer sem_wait(&semVazio); // Entra na Seção Crítica (Bloqueia acesso concorrente) pthread_mutex_lock(&mutexBuffer); buffer[indiceProducao] = i; printf("[PRODUTOR] Produziu item #%02d no slot [%d]\n", i, indiceProducao); indiceProducao = (indiceProducao + 1) % TAM_BUFFER; // Sai da Seção Crítica pthread_mutex_unlock(&mutexBuffer); // Sinaliza ao consumidor que há +1 item pronto sem_post(&semCheio); } pthread_exit(NULL); } // Thread Consumidora void* funcaoConsumidor(void *arg) { for (int i = 1; i <= TOTAL_ITENS; i++) { // Aguarda haver ao menos 1 item pronto no buffer sem_wait(&semCheio); // Entra na Seção Crítica pthread_mutex_lock(&mutexBuffer); int item = buffer[indiceConsumo]; printf(" -> [CONSUMIDOR] Consumiu item #%02d do slot [%d]\n", item, indiceConsumo); indiceConsumo = (indiceConsumo + 1) % TAM_BUFFER; // Sai da Seção Crítica pthread_mutex_unlock(&mutexBuffer); // Sinaliza ao produtor que liberou +1 espaço vazio sem_post(&semVazio); // Simula tempo de processamento do item usleep(250000); // 250ms } pthread_exit(NULL); } int main(void) { pthread_t threadProdutor, threadConsumidor; printf("====================================================\n"); printf(" PHM TECH — S.O. · PRODUTOR-CONSUMIDOR COM SEMAFOROS \n"); printf("====================================================\n\n"); // Inicialização do Mutex e dos Semáforos POSIX pthread_mutex_init(&mutexBuffer, NULL); sem_init(&semVazio, 0, TAM_BUFFER); // Inicia com TAM_BUFFER vagas livres sem_init(&semCheio, 0, 0); // Inicia com 0 itens prontos printf("Criando threads concorrentes do kernel...\n\n"); pthread_create(&threadProdutor, NULL, funcaoProdutor, NULL); pthread_create(&threadConsumidor, NULL, funcaoConsumidor, NULL); // Aguarda ambas as threads terminarem pthread_join(threadProdutor, NULL); pthread_join(threadConsumidor, NULL); // Libera os recursos alocados pthread_mutex_destroy(&mutexBuffer); sem_destroy(&semVazio); sem_destroy(&semCheio); printf("\n[CONCLUIDO] Todos os %d itens foram produzidos e consumidos sem condicao de corrida!\n", TOTAL_ITENS); return 0; }