Processos, jobs, sinais: como o SO organiza execução
- ⬜📁 Filesystem e permissões: rwx, chown, symlink, hardlink(Fundamentos Técnicos)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Todo programa que roda é um processo. Entender como o SO cria, organiza e termina processos — e como você se comunica com eles via sinais — é essencial para depurar, operar e escrever software que se comporta corretamente em produção.
Processos: identidade e estado
Cada processo tem um PID (Process ID) único, e um PPID (Parent PID) — todo processo tem um pai. O processo 1 (init/systemd) é o ancestral de todos.
# Listar processos ps aux # todos os processos do sistema ps aux | grep python # filtrar por nome ps -ef --forest # árvore de processos (mostra hierarquia pai-filho) pstree # árvore visual bonita pstree -p # com PIDs # ps aux output: # USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND # fernando 1234 2.1 0.5 12345 4096 pts/0 S+ 10:00 0:01 python app.py # └── estado: # R = running (na CPU agora) # S = sleeping (esperando I/O ou sinal) # D = uninterruptible sleep (I/O crítico, não pode ser interrompido) # Z = zombie (terminou, aguardando pai coletar) # T = stopped (SIGSTOP aplicado) # + = foreground # Monitorar em tempo real top # monitor clássico (q para sair) htop # versão moderna e interativa (F10 para sair) # Atalhos no htop: F5 = árvore, F9 = kill, F4 = filtro
Criando processos: fork + exec
No Linux, há exatamente uma forma de criar um processo: fork(). Ele cria uma cópia quase idêntica do processo atual. Depois, o filho geralmente chama exec() para substituir sua imagem pelo novo programa.
# O modelo fork+exec em shell (o que acontece quando você roda um comando):
$ python script.py
# O shell:
# 1. fork() → cria filho (clone do shell, mesmo código, mesma memória por CoW)
# 2. No filho: exec("python", ["python", "script.py"]) → substituí espaço de memória
# 3. No pai: wait(filho) → bloqueia até filho terminar
# 4. Filho termina → pai lê exit code → shell pronto para próximo comando
# Copy-on-Write (CoW): fork() não copia memória imediatamente
# O filho só recebe uma cópia real de uma página quando a modifica
# Por isso fork() é rápido mesmo para processos com GB de memóriaO exit code de um processo (0 = sucesso, ≠0 = erro) é como o processo comunica o resultado. Scripts shell dependem disso: && executa o próximo só se o anterior retornou 0; || executa só se retornou ≠0.
echo $? # exit code do último comando npm install && npm test # test só roda se install OK npm install || exit 1 # aborta se install falhar
Foreground, background e jobs
# Foreground (padrão): comando ocupa o terminal python servidor.py # terminal bloqueado até o processo terminar # Ctrl+C → envia SIGINT (interrompe) # Ctrl+Z → envia SIGTSTP (pausa, processo vai para background stopped) # Background: adiciona & no final python servidor.py & # roda em background, retorna PID # [1] 12345 ← job number e PID # Gerenciar jobs do shell atual jobs # lista jobs em background jobs -l # com PIDs fg %1 # traz job 1 para foreground bg %1 # resume job 1 pausado em background disown %1 # remove da lista de jobs (não recebe SIGHUP ao fechar terminal) # Para processos persistirem além do terminal: nohup python servidor.py & # imune a SIGHUP, saída vai para nohup.out nohup python servidor.py > app.log 2>&1 & # com log específico # Solução profissional: systemd ou supervisor # Não use nohup em produção — use um process manager
Sinais: comunicação com processos
Sinais são notificações assíncronas enviadas a processos. O processo pode capturar a maioria e decidir o que fazer — exceto SIGKILL e SIGSTOP, que são tratados pelo kernel.
| Sinal | Número | Ação padrão | Uso |
|---|---|---|---|
| SIGHUP | 1 | Terminar | Recarregar config (nginx, sshd) |
| SIGINT | 2 | Terminar | Ctrl+C — interrupção do usuário |
| SIGQUIT | 3 | Core dump | Ctrl+\ — quit com dump |
| SIGTERM | 15 | Terminar | Pedido gracioso de encerramento |
| SIGKILL | 9 | Terminar (kernel) | Forçado, não pode ser capturado |
| SIGSTOP | 19 | Parar (kernel) | Pausa, não pode ser capturado |
| SIGCONT | 18 | Continuar | Retoma processo pausado |
| SIGUSR1 | 10 | Terminar | Definido pelo app (log rotate, etc) |
| SIGUSR2 | 12 | Terminar | Definido pelo app |
# Enviar sinais kill PID # SIGTERM (padrão) — pedido gracioso kill -15 PID # SIGTERM explícito kill -9 PID # SIGKILL — força (último recurso) kill -1 PID # SIGHUP — nginx usa isso para reload sem downtime kill -USR1 PID # SIGUSR1 — log rotate em nginx/apache # Por nome do processo killall nginx # SIGTERM para todos os processos chamados nginx killall -9 python # SIGKILL para todos os pythons pkill -f "python app" # por padrão no nome completo do comando # SIGKILL é o ÚLTIMO recurso — não permite cleanup: # → conexões de banco de dados ficam abertas # → buffers de arquivo não são flushed # → dados em memória são perdidos # → state corrompido é possível
Capturando sinais em Python (graceful shutdown)
import signal
import sys
def graceful_shutdown(signum, frame):
print(f"\nRecebeu sinal {signum}. Encerrando graciosamente...")
# 1. Parar de aceitar novas requisições
# 2. Aguardar requisições em andamento terminarem
# 3. Fechar conexões com banco de dados
# 4. Flush de logs
sys.exit(0)
# Registra handlers
signal.signal(signal.SIGTERM, graceful_shutdown)
signal.signal(signal.SIGINT, graceful_shutdown)
# Loop principal
print(f"Servidor rodando PID={os.getpid()}")
while True:
# ... processar requisições
passdocker stop. Se o processo não tratar SIGTERM, Docker espera 10 segundos e envia SIGKILL. Aplicar graceful shutdown reduz dados corrompidos e conexões zumbis.Depurando processos problemáticos
# Processo consome muita CPU? top # ordena por CPU (pressione P) htop # interativo, F5 para árvore # Processo usa muita memória? ps aux --sort=-%mem | head -10 # top 10 por memória cat /proc/PID/status | grep VmRSS # RAM usada pelo processo # Processo travado (D state = uninterruptible sleep)? # Geralmente esperando I/O de disco com problema # Não responde a sinais, nem SIGKILL — precisa resolver o I/O ou reiniciar o sistema # O que um processo está fazendo? strace -p PID # syscalls em tempo real lsof -p PID # arquivos e sockets abertos cat /proc/PID/cmdline | tr '