🧠 PHILOSOPHERS

Guia Completo de Conceitos

Programação Concorrente & Sincronização de Threads

Do básico ao avançado com exemplos práticos

📚 Índice

1️⃣ Processos vs Threads
2️⃣ Threads POSIX (pthreads)
3️⃣ Mutexes e Critical Sections
4️⃣ Data Races
5️⃣ Deadlocks
6️⃣ Sincronização de Tempo
7️⃣ Problemas Clássicos
8️⃣ Boas Práticas

1️⃣ Processos vs Threads

🖥️ O que é um Processo?

Um processo é um programa em execução. Cada processo tem:

  • O próprio espaço de memória
  • Os próprios recursos (arquivos, sockets)
  • PID (Process ID) único
  • Isolamento total de outros processos
🏠 Analogia do Mundo Real
Um processo é como uma casa:
• Tem os próprios quartos, cozinha, casa de banho
• Totalmente isolada das casas ao seu redor
• Para comunicar com outra casa, precisa sair e tocar a campainha

🧵 O que é uma Thread?

Uma thread é uma linha de execução dentro de um processo. Threads do mesmo processo compartilham:

  • O mesmo espaço de memória
  • Os mesmos recursos
  • Variáveis globais
  • Mas cada uma tem sua própria pilha (stack)
👥 Analogia do Mundo Real
Uma thread é como uma pessoa dentro da casa:
• Todas compartilham a mesma cozinha, sala, casa de banho
• Podem se comunicar facilmente
• Mas cada uma tem o próprio quarto (stack)
PROBLEMA: Podem entrar em conflito (ex: duas pessoas querem usar a mesma panela)

Processos vs Threads - Comparação

🖥️ PROCESSOS

➕ Vantagens:

  • Isolamento total
  • Crash não afeta outros
  • Mais seguro

➖ Desvantagens:

  • Pesados (muita memória)
  • Criação lenta
  • Comunicação complicada

🧵 THREADS

➕ Vantagens:

  • Leves (pouca memória)
  • Criação rápida
  • Compartilham dados facilmente

➖ Desvantagens:

  • Crash afeta todas
  • Data races possíveis
  • Sincronização complexa
🎯 No Philosophers usamos THREADS porque:
  • Precisamos de várias execuções paralelas (N filósofos)
  • Todos precisam acessar dados compartilhados (garfos, tempo)
  • Queremos eficiência (threads são mais leves)

2️⃣ Threads POSIX (pthreads)

📚 O que é POSIX?

POSIX (Portable Operating System Interface) é um padrão para sistemas Unix-like.
pthreads = biblioteca de threads do POSIX.

Funções Principais

pthread_create() - Criar Thread

int pthread_create( pthread_t *thread, // ID da thread (output) const pthread_attr_t *attr, // Atributos (NULL = default) void *(*start_routine)(void*), // Função a executar void *arg // Argumento para a função );

Retorno: 0 em sucesso, código de erro caso contrário
O que faz: Cria uma nova thread que executa start_routine(arg)

Exemplo Prático

void *print_hello(void *arg) { int id = *(int*)arg; printf("Hello from thread %d!\n", id); return NULL; } int main() { pthread_t thread1, thread2; int id1 = 1, id2 = 2; // Cria thread 1 pthread_create(&thread1, NULL, print_hello, &id1); // Cria thread 2 pthread_create(&thread2, NULL, print_hello, &id2); // ⚠️ IMPORTANTE: Aguardar threads terminarem! pthread_join(thread1, NULL); pthread_join(thread2, NULL); return 0; }

pthread_join() - Aguardar Thread

Sintaxe

int pthread_join( pthread_t thread, // Thread para aguardar void **retval // Valor de retorno (pode ser NULL) );

O que faz: Bloqueia a thread atual até que thread termine
Analogia: É como esperar alguém terminar de falar antes de você falar

⚠️ ERRO COMUM
Esquecer o pthread_join():
• O programa termina antes das threads executarem
• As threads são destruídas prematuramente
❌ ERRADO
int main() { pthread_t t; pthread_create(&t, NULL, func, NULL); return 0; // ❌ Termina imediatamente! }
✅ CORRETO
int main() { pthread_t t; pthread_create(&t, NULL, func, NULL); pthread_join(t, NULL); // ✅ Aguarda! return 0; }

3️⃣ Mutexes

🔒 O que é um Mutex?

Mutex = MUTual EXclusion (Exclusão Mútua)

É um "cadeado" que garante que apenas UMA thread acesse um recurso por vez.

🚻 Analogia: Casa de banho Pública
Imagina uma casa de banho penas com 1 cabine:

Sem Mutex:
• Várias pessoas tentam entrar ao mesmo tempo
• Caos total! 😱

Com Mutex (trancar a porta):
• Primeira pessoa entra e tranca (lock)
• Outras esperam na fila
• Quando sai, destranca (unlock)
• Próxima pessoa pode entrar

Mutex - Funções

1. Inicializar

pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL);

2. Trancar (Lock)

pthread_mutex_lock(&mutex); // Agora apenas ESTA thread pode executar este código // Outras threads ficam BLOQUEADAS aqui

3. Destrancar (Unlock)

pthread_mutex_unlock(&mutex); // Libera o mutex para outra thread usar

4. Destruir

pthread_mutex_destroy(&mutex); // Sempre destruir no final!

Mutex - Exemplo Prático

❌ SEM MUTEX (Data Race!)
int counter = 0; void *increment(void *arg) { for (int i = 0; i < 1000000; i++) counter++; // ❌ PERIGOSO! return NULL; } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, increment, NULL); pthread_create(&t2, NULL, increment, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); printf("Counter: %d\n", counter); // Esperado: 2000000 // Real: ~1500000 (ERRADO!) }
✅ COM MUTEX
int counter = 0; pthread_mutex_t mutex; void *increment(void *arg) { for (int i = 0; i < 1000000; i++) { pthread_mutex_lock(&mutex); counter++; // ✅ SEGURO! pthread_mutex_unlock