From 0a91d2dabd2cc5abd0a215cc67592860993b8cbf Mon Sep 17 00:00:00 2001 From: Rui Ribeiro <42305006+ruiribeiro04@users.noreply.github.com> Date: Tue, 7 Oct 2025 12:20:55 +0100 Subject: [PATCH] Added exercices in portuguese --- 10_philosophers_args.txt | 22 ++++++++++++++ 11_race_detector.txt | 24 +++++++++++++++ 12_philosophers_bonus.txt | 24 +++++++++++++++ 1_thread_basics.txt | 19 ++++++++++++ 2_mutex_basics.txt | 18 ++++++++++++ 3_precise_timing.txt | 23 +++++++++++++++ 4_state_monitor.txt | 23 +++++++++++++++ 5_producer_consumer.txt | 23 +++++++++++++++ 6_deadlock_demo.txt | 24 +++++++++++++++ 7_limited_resources.txt | 23 +++++++++++++++ 8_simple_philosophers.txt | 19 ++++++++++++ 9_death_monitor.txt | 21 +++++++++++++ LICENSE | 2 +- README.md | 62 ++++++++++++++++++++++++++++++++++++++- 14 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 10_philosophers_args.txt create mode 100644 11_race_detector.txt create mode 100644 12_philosophers_bonus.txt create mode 100644 1_thread_basics.txt create mode 100644 2_mutex_basics.txt create mode 100644 3_precise_timing.txt create mode 100644 4_state_monitor.txt create mode 100644 5_producer_consumer.txt create mode 100644 6_deadlock_demo.txt create mode 100644 7_limited_resources.txt create mode 100644 8_simple_philosophers.txt create mode 100644 9_death_monitor.txt diff --git a/10_philosophers_args.txt b/10_philosophers_args.txt new file mode 100644 index 0000000..34c36e6 --- /dev/null +++ b/10_philosophers_args.txt @@ -0,0 +1,22 @@ +Assignment name: philosophers_args +Expected files: philosophers_args.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, +pthread_detach, pthread_join, pthread_mutex_init, pthread_mutex_destroy, +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +------------------------------------------------------------------------ + +Implementa o problema completo dos filósofos com parsing de argumentos: + +Argumentos: `number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_must_eat]` + +Comportamento: +- Cada filósofo alterna: pensar → tentar pegar forks → comer → largar forks → dormir +- Se um filósofo não comer dentro de `time_to_die`, morre e programa termina +- Se `number_of_times_must_eat` especificado, programa termina quando todos comeram esse número de vezes +- Thread monitor verifica mortes a cada 1ms + +Uso: `./philosophers_args 5 800 200 200` ou `./philosophers_args 5 800 200 200 7` + +Hint: Este é praticamente o projeto Philosophers completo. +Implementa parsing robusto de argumentos, validação de inputs, e cleanup adequado de recursos. +A thread monitor é crítica - deve detectar morte rapidamente sem afetar performance. \ No newline at end of file diff --git a/11_race_detector.txt b/11_race_detector.txt new file mode 100644 index 0000000..ca42e25 --- /dev/null +++ b/11_race_detector.txt @@ -0,0 +1,24 @@ +Assignment name: race_detector +Expected files: race_detector.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +---------------------------------------------------------------------------------------- + +Cria uma versão do problema dos filósofos que: +1. Detecta e reporta possíveis data races +2. Testa diferentes estratégias de otimização: + - Estratégia A: mutex global para todas as operações + - Estratégia B: mutex por fork + mutex para impressão + - Estratégia C: minimizar lock time + +Inclui stress test: roda 100 iterações com diferentes configurações e reporta: +- Número de data races detectadas +- Performance (tempo total) +- Número de mortes + +Uso: `./race_detector 4 410 200 200` + +Hint: Use ferramentas como `valgrind --tool=helgrind` para detectar data races. +No projeto real, qualquer data race resulta em nota 0. +Testa com números ímpares e pares de filósofos, e com time_to_die muito próximo de time_to_eat. \ No newline at end of file diff --git a/12_philosophers_bonus.txt b/12_philosophers_bonus.txt new file mode 100644 index 0000000..d19f311 --- /dev/null +++ b/12_philosophers_bonus.txt @@ -0,0 +1,24 @@ +Assignment name: philosophers_bonus +Expected files: philosophers_bonus.c +Allowed functions: memset, printf, malloc, free, write, fork, kill, exit, +pthread_create, pthread_detach, pthread_join, usleep, gettimeofday, +waitpid, sem_open, sem_close, sem_post, sem_wait, sem_unlink +------------------------------------------------------------------------- + +Implementa a versão bonus do Philosophers: +- Cada filósofo é um processo separado (não thread) +- Usa semáforos POSIX nomeados para coordenação +- Processo pai monitora todos os processos filhos +- Se um filósofo morre, mata todos os outros processos + +Funcionalidades adicionais: +- Cleanup adequado de semáforos nomeados +- Handling de sinais (SIGINT, SIGTERM) +- Relatório final com estatísticas + +Uso: `./philosophers_bonus 5 800 200 200 7` + +Hint: Bonus part usa processos em vez de threads. +Semáforos POSIX nomeados permitem comunicação entre processos. +Usa fork() para criar processos filhos e waitpid() para monitorizar. +O cleanup de semáforos é crucial - usa sem_unlink() e handling de sinais para cleanup em caso de interrupção. \ No newline at end of file diff --git a/1_thread_basics.txt b/1_thread_basics.txt new file mode 100644 index 0000000..90dee32 --- /dev/null +++ b/1_thread_basics.txt @@ -0,0 +1,19 @@ +Assignment name: thread_basics +Expected files: thread_basics.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, +pthread_detach, pthread_join, usleep, gettimeofday +------------------------------------------------------------------------------- + +Cria um programa que lance 2 threads. Cada thread deve imprimir o seu ID e uma mensagem diferente. +O programa principal deve esperar que ambas as threads terminem antes de sair. + +Thread 1 deve imprimir: "Thread 1: Hello from thread 1" +Thread 2 deve imprimir: "Thread 2: Hello from thread 2" + +O programa deve aceitar como argumento o número de mensagens que cada thread deve imprimir. + +Uso: `./thread_basics 5` + +Hint: Este exercício ensina-te a base de pthread_create e pthread_join. +Lembra-te de verificar os valores de retorno das funções pthread. +Usa uma estrutura para passar argumentos às threads. diff --git a/2_mutex_basics.txt b/2_mutex_basics.txt new file mode 100644 index 0000000..eb575a7 --- /dev/null +++ b/2_mutex_basics.txt @@ -0,0 +1,18 @@ +Assignment name: mutex_basics +Expected files: mutex_basics.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach +pthread_join, pthread_mutex_init, pthread_mutex_destroy +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +-------------------------------------------------------------------------------------- + +Cria um programa com uma variável global `counter` inicializada a 0. +Lança 4 threads que incrementam esta variável 1000 vezes cada uma. +Usa um mutex para proteger o acesso à variável. + +O programa deve imprimir o valor final de `counter` (deve ser 4000) e o tempo total de execução. + +Uso: `./mutex_basics` + +Hint: Sem mutex, vais ver valores incorretos devido a race conditions. +O mutex garante que apenas uma thread acede à variável de cada vez. +Este é o conceito fundamental para o projeto Philosophers. \ No newline at end of file diff --git a/3_precise_timing.txt b/3_precise_timing.txt new file mode 100644 index 0000000..8e0da68 --- /dev/null +++ b/3_precise_timing.txt @@ -0,0 +1,23 @@ +Assignment name: precise_timing +Expected files: precise_timing.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +--------------------------------------------------------------------------------------- + +Implementa as seguintes funções: +- `long long get_current_time()` - retorna o tempo atual em milissegundos +- `void precise_sleep(int ms)` - dorme por exatamente X milissegundos +- `long long time_diff(long long start, long long end)` - calcula diferença entre tempos + +Cria um programa que testa estas funções: +1. Mede o tempo de início +2. Dorme por 100ms usando precise_sleep +3. Mede o tempo de fim +4. Imprime a diferença (deve ser ~100ms) + +Uso: `./precise_timing` + +Hint: gettimeofday() é crucial no projeto Philosophers. +usleep() não é sempre preciso, por isso tens de verificar o tempo periodicamente. +No Philosophers, o timing preciso é essencial para detectar mortes. diff --git a/4_state_monitor.txt b/4_state_monitor.txt new file mode 100644 index 0000000..5eea894 --- /dev/null +++ b/4_state_monitor.txt @@ -0,0 +1,23 @@ +**Assignment name**: state_monitor +**Expected files**: state_monitor.c +**Allowed functions**: memset, printf, malloc, free, write, pthread_create, +pthread_detach, pthread_join, pthread_mutex_init, pthread_mutex_destroy, +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +--------------------------------------------------------------------------- + +Cria um programa com 3 threads "worker" e 1 thread "monitor": + +**Worker threads**: Cada thread alterna entre 3 estados: +- WORKING (2 segundos) +- RESTING (1 segundo) +- THINKING (1.5 segundos) + +Cada mudança de estado deve ser impressa com timestamp: `[timestamp] Worker X is WORKING` + +**Monitor thread**: Verifica se algum worker está no mesmo estado há mais de 3 segundos. +Se sim, imprime: `[timestamp] WARNING: Worker X stuck in STATE` + +**Uso**: `./state_monitor` + +**Hint**: Use enums para os estados. O monitor thread simula a verificação de morte no Philosophers, +tens de verificar continuamente sem interferir com os workers. Usa mutex para proteger o acesso aos estados. diff --git a/5_producer_consumer.txt b/5_producer_consumer.txt new file mode 100644 index 0000000..f77be33 --- /dev/null +++ b/5_producer_consumer.txt @@ -0,0 +1,23 @@ +Assignment name: producer_consumer +Expected files: producer_consumer.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, +pthread_detach, pthread_join, pthread_mutex_init, pthread_mutex_destroy, +pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +--------------------------------------------------------------------------- + +Implementa o problema clássico Producer-Consumer: +- 2 threads Producer: produzem items (números de 1 a 100) e colocam num buffer +- 2 threads Consumer: consomem items do buffer e processam-nos +- Buffer partilhado com capacidade limitada (10 items) + +Regras: +- Producers devem esperar se buffer estiver cheio +- Consumers devem esperar se buffer estiver vazio +- Não deve haver race conditions +- Imprime quando items são produzidos/consumidos + +Uso: `./producer_consumer` + +Hint: Este exercício ensina-te a coordenação entre múltiplas threads com recursos limitados. +É similar ao problema dos forks no Philosophers. +Usa mutexes para proteger o buffer e condition variables ou sleep para coordenação. \ No newline at end of file diff --git a/6_deadlock_demo.txt b/6_deadlock_demo.txt new file mode 100644 index 0000000..c215fb0 --- /dev/null +++ b/6_deadlock_demo.txt @@ -0,0 +1,24 @@ +Assignment name: deadlock_demo +Expected files: deadlock_demo.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, +pthread_mutex_unlock, usleep, gettimeofday + +--- + +Cria um programa que demonstra deadlock e depois mostra como o resolver: + +Parte 1 - Deadlock: +2 threads, 2 mutexes (mutex_a, mutex_b) +- Thread 1: lock mutex_a → sleep 100ms → lock mutex_b → unlock ambos +- Thread 2: lock mutex_b → sleep 100ms → lock mutex_a → unlock ambos + +Parte 2 - Solução: Ambas threads fazem lock dos mutexes na mesma ordem. + +O programa deve aceitar um argumento: 0 para deadlock, 1 para solução. + +Uso: `./deadlock_demo 0` (demonstra deadlock) +Uso: `./deadlock_demo 1` (demonstra solução) + +Hint: Deadlock é um risco real no Philosophers quando filósofos tentam pegar forks em ordens diferentes. +A solução mais comum é ordenar os recursos (forks com IDs mais baixos primeiro). diff --git a/7_limited_resources.txt b/7_limited_resources.txt new file mode 100644 index 0000000..442525b --- /dev/null +++ b/7_limited_resources.txt @@ -0,0 +1,23 @@ +**Assignment name**: limited_resources +**Expected files**: limited_resources.c +**Allowed functions**: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday + +--- + +Simula uma biblioteca com 3 computadores partilhados entre 10 estudantes: +- Cada estudante (thread) quer usar um computador por 2-5 segundos (tempo aleatório) +- Apenas 3 estudantes podem usar computadores simultaneamente +- Implementa um "semáforo" usando mutexes e uma variável contador + +Imprime quando estudantes: +- Chegam à biblioteca +- Conseguem um computador +- Terminam de usar o computador +- Saem da biblioteca + +**Uso**: `./limited_resources` + +**Hint**: Como POSIX semáforos não são permitidos no mandatory part, +implementa o teu próprio semáforo com mutex + contador + condition logic. +Este exercício simula a limitação de recursos como no Philosophers com forks. \ No newline at end of file diff --git a/8_simple_philosophers.txt b/8_simple_philosophers.txt new file mode 100644 index 0000000..c26309c --- /dev/null +++ b/8_simple_philosophers.txt @@ -0,0 +1,19 @@ +Assignment name: simple_philosophers +Expected files: simple_philosophers.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock, usleep, gettimeofday +--- + +Implementa uma versão simplificada do problema dos filósofos: +- 3 filósofos sentados numa mesa circular +- 3 forks (um entre cada par de filósofos) +- Cada filósofo alterna entre: pensar (1s) → pegar forks → comer (1s) → largar forks → repetir +- Programa corre por 10 segundos e depois pára + +Cada ação deve ser impressa: `[timestamp] Philosopher X is thinking/eating` + +Uso: `./simple_philosophers` + +Hint: Este é o núcleo do projeto Philosophers. Cada fork é protegido por um mutex. +Para evitar deadlock, implementa uma ordem consistente para pegar forks (fork com ID menor primeiro). +Usa uma thread monitor para parar após 10s. \ No newline at end of file diff --git a/9_death_monitor.txt b/9_death_monitor.txt new file mode 100644 index 0000000..7ae8145 --- /dev/null +++ b/9_death_monitor.txt @@ -0,0 +1,21 @@ +Assignment name: death_monitor +Expected files: death_monitor.c +Allowed functions: memset, printf, malloc, free, write, pthread_create, pthread_detach, +pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, +pthread_mutex_unlock, usleep, gettimeofday +--- + +Cria um sistema com: +- 4 threads "worker" que fazem trabalho por períodos variados (1-4 segundos) +- 1 thread monitor que verifica se algum worker não dá "sinal de vida" há mais de 3 segundos +- Workers devem atualizar `last_activity_time` a cada iteração +- Monitor verifica a cada 100ms e imprime aviso se detectar worker "morto" + +Simula "morte" fazendo um worker parar aleatoriamente. + +Uso: `./death_monitor` + +Hint: Este exercício simula a detecção de morte no Philosophers. +O monitor thread deve verificar continuamente sem bloquear os workers. +Usa mutex para proteger `last_activity_time`. +A detecção deve ser rápida (dentro de 10ms no projeto real). \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7fe8792..6e83c99 100644 --- a/LICENSE +++ b/LICENSE @@ -219,7 +219,7 @@ If you develop a new program, and you want it to be of the greatest possible use To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - philosophers_training + philosophers_prep Copyright (C) 2025 ruiferna This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. diff --git a/README.md b/README.md index 4d8563c..4a15d55 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,62 @@ -# philosophers_training +# Exercícios Preparatórios — Projeto Philosophers +Bem-vindo ao repositório de exercícios práticos desenhados para construir, passo a passo, todos os conceitos necessários para dominar o projeto Philosophers da 42. Aqui vais encontrar desafios progressivos sobre threads, mutexes, deadlocks, sincronização, semáforos, timing, e muito mais em C. + +## Objetivo + +A proposta deste repositório é guiar estudantes pela aprendizagem real de programação concorrente, partindo do absoluto básico até à implementação de sistemas completos e robustos capazes de resolver o clássico problema dos Filósofos, incluindo as regras e desafios da bonus part. + +## Estrutura dos Exercícios + +Cada exercício segue uma estrutura clara e normalizada, incluindo: + +- **Assignment name** +- **Expected files** +- **Allowed functions** +- **Descrição do problema** +- **Sugestão/Hint para a resolução** + +### Lista de Exercícios + +| Nº | Nome | Conteúdo-chave | +|----|---------------------------|---------------------------------------------| +| 1 | thread_basics | Threads, pthread_create, pthread_join | +| 2 | mutex_basics | Mutexes, race conditions | +| 3 | precise_timing | gettimeofday, usleep, timing | +| 4 | state_monitor | Monitorização, enums, padrões monitor | +| 5 | producer_consumer | Sincronização, coordination problems | +| 6 | deadlock_demo | Deadlock, prevenção de deadlock | +| 7 | limited_resources | Semáforo manual, acesso limitado | +| 8 | simple_philosophers | Problema dos filósofos simplificado | +| 9 | death_monitor | Monitorização de vida, threads watchdog | +| 10 | philosophers_args | Implementação 'full', argumentos | +| 11 | race_detector | Data races, otimização de locks | +| 12 | philosophers_bonus | Processos, semáforos POSIX, bonus part | + +## Como usar + +1. **Cada exercício é independente.** Recomenda-se seguir pela ordem, para garantir a aprendizagem progressiva. +2. **Compilar cada exercício:** + ```sh + gcc -Wall -Wextra -Werror -pthread .c -o + ``` +3. **Executar cada binário** seguindo as instruções e exemplos do cabeçalho do exercício. + +## Requisitos Técnicos + +- Compilador C (ex: gcc) +- Ambiente POSIX (Linux ou Mac OS X recomendado) +- Bibliotecas pthreads standard + +## Recomendações + +- Não uses funções externas às permitidas. +- Lê atentamente os hints fornecidos para cada exercício. +- Analisa erros de race condition e deadlocks usando ferramentas como `valgrind --tool=helgrind`. +- Consulta [The Little Book of Semaphores](https://greenteapress.com/wp/semaphores/) para cimentar conceitos. + +## Créditos e Referências + +- Inspirado no livro open-source **The Little Book of Semaphores** por Allen B. Downey. +- Estrutura e avaliação baseadas no formato dos projetos 42. +- Problema clássico dos Filósofos por Edsger W. Dijkstra.