Aula 02 — Processos: Conceito, Ciclo de Vida e Chamadas de Sistema
Objetivos
Ao final desta aula você deve ser capaz de:
- Distinguir programa de processo, identificando os componentes que compõem um processo em memória.
- Explicar por que a multiprogramação exige o conceito de processo e como ela maximiza o uso da CPU.
- Desenhar e interpretar os diagramas de estados de processo nos modelos de 2, 5 e 7 estados, indicando as transições e seus gatilhos.
- Descrever o conteúdo e a função do Bloco de Controle de Processo (PCB).
- Comparar os schedulers de longo, médio e curto prazo quanto à frequência de execução e ao critério de decisão.
- Implementar a criação de processos em C usando
fork(),exec()ewait(), interpretando o valor de retorno defork().
Conteúdo
Multiprogramação: a motivação do processo
Nos primeiros computadores, apenas um programa era executado por vez. Toda vez que ele esperava um dado do disco ou do teclado, a CPU ficava ociosa — desperdício puro.
A multiprogramação resolve isso: vários programas são mantidos na memória simultaneamente. Enquanto um processo aguarda uma operação de E/S, a CPU é entregue a outro. O resultado é um aproveitamento muito maior do processador.
Analogia: imagine um chef de cozinha que, enquanto aguarda a água ferver, já pica os legumes para o próximo prato. A "receita em execução" é o processo; o chef, a CPU; e o fogo/espera, a operação de E/S.
Para que o SO gerencie múltiplos programas concorrentemente de forma segura, ele precisa de uma abstração que represente um programa em execução — o processo.
Programa vs. Processo
| Aspecto | Programa | Processo |
|---|---|---|
| Natureza | Passivo, estático | Ativo, dinâmico |
| Onde existe | No disco (arquivo executável) | Na memória RAM, em execução |
| Unicidade | Um arquivo pode gerar múltiplos processos | Cada instância é um processo distinto |
| Contém | Código e dados em disco | Código + dados + pilha + heap + contexto de CPU |
Um processo em memória é dividido em quatro regiões (do endereço mais alto ao mais baixo, em sistemas típicos):
Modelos de Estados do Processo
Modelo de 2 estados
O modelo mais simples divide os processos em apenas dois estados:
Limitação crítica: "Não-Executando" mistura processos prontos para executar (que só aguardam a CPU) com processos bloqueados (que aguardam um evento de E/S). O scheduler poderia selecionar um processo bloqueado — ineficiência.
Modelo de 5 estados (modelo clássico — foco da prova)
| Estado | Descrição |
|---|---|
| Novo | O processo está sendo criado (PCB alocado, recursos reservados) |
| Pronto | Na fila de prontos, aguardando a CPU ser alocada pelo scheduler |
| Executando | Instruções sendo executadas na CPU (apenas 1 por núcleo por vez) |
| Bloqueado | Aguarda conclusão de E/S ou evento externo; não pode usar a CPU mesmo que livre |
| Terminado | Execução concluída; PCB ainda existe até o pai coletar o status (wait()) |
Transições e seus gatilhos:
- Novo → Pronto: o SO admite o processo na fila de prontos (scheduler de longo prazo).
- Pronto → Executando: o scheduler de curto prazo despacha (dispatch) o processo.
- Executando → Pronto: fim do quantum de tempo (preempção por tempo) ou preempção por processo de maior prioridade.
- Executando → Bloqueado: o processo solicita E/S ou aguarda um evento (
read(),sleep(),wait()). - Bloqueado → Pronto: a operação de E/S é concluída ou o evento ocorre (interrupção).
- Executando → Terminado:
exit()ou término anormal (sinal, exceção).
Modelo de 7 estados (com swapping)
Quando a memória está sobrecarregada, o SO pode remover processos da RAM e salvá-los no disco (operação chamada swap out). Surgem dois estados suspensos:
- Pronto/Suspenso: processo pronto para executar, mas sua imagem está no disco.
- Bloqueado/Suspenso: processo aguardando evento E ainda está no disco.
O swapping é gerenciado pelo scheduler de médio prazo, que equilibra a ocupação da RAM.
Bloco de Controle de Processo (PCB)
O PCB (também chamado task_struct no Linux) é a estrutura de dados que representa um processo para o SO. É o "prontuário" do processo — tudo que o SO precisa saber para gerenciá-lo e retomá-lo após uma mudança de contexto.
| Campo do PCB | Conteúdo |
|---|---|
| Estado do processo | Novo / Pronto / Executando / Bloqueado / Terminado |
| PID | Identificador único do processo |
| Contador de programa (PC) | Endereço da próxima instrução a executar |
| Registradores da CPU | Cópia de todos os registradores ao momento da preempção |
| Informações de scheduling | Prioridade, tempo de CPU consumido, ponteiros para filas |
| Informações de memória | Tabela de páginas, registradores base/limite |
| Informações de E/S | Lista de dispositivos alocados, arquivos abertos |
| Informações de contabilização | Tempo real e de CPU usados, limites |
No Linux, o PCB é a estrutura task_struct definida em <linux/sched.h>:
/* Somente leitura — trecho ilustrativo da task_struct do Linux */
long state; /* estado do processo */
struct sched_entity se; /* informações de scheduling */
struct task_struct *parent; /* ponteiro para o processo-pai */
struct list_head children; /* lista de filhos */
struct files_struct *files; /* arquivos abertos */
struct mm_struct *mm; /* espaço de endereçamento */
Schedulers: longo, médio e curto prazo
| Scheduler | Frequência | Decisão | Função |
|---|---|---|---|
| Longo prazo (job scheduler) | Raramente (minutos) | Quais jobs entram na memória? | Controla o grau de multiprogramação |
| Médio prazo | Ocasionalmente | Quais processos são suspensos/retomados? | Gerencia swapping |
| Curto prazo (CPU scheduler) | Frequentemente (ms) | Qual processo pronto executa agora? | Maximiza utilização da CPU |
O scheduler de longo prazo deve selecionar um bom mix de processos: se todos forem CPU-bound, a fila de E/S fica vazia; se todos forem I/O-bound, a CPU fica ociosa.
Criação de Processos: fork() e exec()
No UNIX/Linux, o único jeito de criar um processo é com fork(). Após o fork, o processo-filho pode substituir sua imagem com um novo programa usando exec().
/* Executável — compile com: gcc -o demo demo.c */
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* wait() */
#include <stdio.h>
#include <unistd.h> /* fork(), execlp() */
int main(void)
{
pid_t pid;
/* fork() cria uma CÓPIA exata do processo atual */
pid = fork();
if (pid < 0) { /* retorno negativo = erro */
fprintf(stderr, "fork falhou\n");
return 1;
}
else if (pid == 0) { /* retorno 0 = estamos no FILHO */
/* execlp substitui a imagem do filho pelo programa ls */
/* após exec bem-sucedido, o código abaixo NUNCA é executado */
execlp("/bin/ls", "ls", "-l", NULL);
/* chegou aqui = exec falhou */
fprintf(stderr, "exec falhou\n");
return 1;
}
else { /* retorno > 0 = estamos no PAI */
/* wait() bloqueia o pai até o filho terminar */
/* evita processo "zumbi" (filho terminado sem coleta de status) */
wait(NULL);
printf("Filho (PID %d) concluído.\n", pid);
}
return 0;
}
O que acontece passo a passo:
Chamadas de sistema envolvidas:
| Syscall | Número (x86-64) | Função |
|---|---|---|
fork() | 57 | Cria processo-filho (cópia do pai) |
execve() / execlp() | 59 | Substitui imagem do processo |
wait() / waitpid() | 61 | Pai aguarda término do filho |
exit() | 60 | Encerra o processo, libera recursos |
getpid() | 39 | Retorna PID do processo atual |
Atividade prática rápida: execute
ps -eloups axjfno terminal Linux para ver a árvore de processos e identificar PIDs, PPIDs e estados.
Exercícios
Questões dissertativas
Explique por que um programa é considerado uma entidade passiva e um processo é considerado uma entidade ativa. Como o mesmo arquivo executável pode gerar dois processos completamente independentes?
Qual é a principal limitação do modelo de 2 estados que motivou a criação do modelo de 5 estados? Explique com um exemplo concreto.
Liste todos os campos típicos de um PCB e explique por que cada um é necessário para o mecanismo de mudança de contexto (context switch).
Compare os três tipos de schedulers (longo, médio e curto prazo) em termos de frequência de execução, critério de decisão e impacto na performance do sistema.
Explique passo a passo o que acontece quando fork() é chamado em um processo C no Linux. Por que o retorno de fork() é diferente no processo-pai e no processo-filho?
O que é um processo 'zumbi' e um processo 'órfão' no Linux? Como cada um pode ser evitado?
Analise o trecho de código abaixo e responda: quantos processos são criados no total (incluindo o processo original)? Quais linhas cada processo executa?
Por que a mudança de contexto (context switch) é considerada 'puro overhead'? Quais fatores de hardware influenciam seu custo?
Explique a diferença entre processos CPU-bound e I/O-bound. Por que o scheduler de longo prazo deve selecionar um mix equilibrado entre os dois tipos?
Descreva os estados Pronto/Suspenso e Bloqueado/Suspenso do modelo de 7 estados. Em que situação o scheduler de médio prazo suspende um processo bloqueado em vez de um processo pronto?
Quiz de múltipla escolha
1. Qual dos seguintes é um componente do processo em memória que NÃO existe no arquivo executável em disco?
- a)Seção de texto (code segment)
- b)Seção de dados globais (data segment)
- c)Pilha (stack) com variáveis locais e endereços de retorno
- d)Constantes literais embutidas no código
- e)Tabela de símbolos do linker
2. No modelo de 5 estados, qual transição ocorre quando o processo em execução solicita uma operação de leitura em disco?
- a)Executando → Pronto
- b)Executando → Terminado
- c)Executando → Bloqueado
- d)Pronto → Bloqueado
- e)Bloqueado → Pronto
3. Qual o valor de retorno de fork() no processo-filho após uma chamada bem-sucedida?
- a)O PID do processo-pai
- b)O PID do processo-filho
- c)−1 (menos um)
- d)0 (zero)
- e)1 (um)
4. O scheduler de curto prazo é executado com muito mais frequência que o scheduler de longo prazo. Qual é a principal razão para isso?
- a)O scheduler de curto prazo precisa gerenciar o swapping de processos para o disco
- b)O scheduler de curto prazo decide qual processo entra na memória, o que requer análise profunda
- c)Processos em execução podem ser preemptados ou bloqueados a cada poucos milissegundos, exigindo seleção frequente do próximo processo
- d)O scheduler de longo prazo já resolve todos os problemas de alocação de CPU
- e)O scheduler de curto prazo só é invocado quando um processo termina
5. Qual campo do PCB é INDISPENSÁVEL para que o processo possa retomar a execução exatamente de onde parou após uma mudança de contexto?
- a)PID do processo
- b)Lista de arquivos abertos
- c)Contador de programa (Program Counter)
- d)Prioridade de scheduling
- e)ID do usuário proprietário
6. Um processo está no estado Bloqueado esperando uma leitura de disco. A operação de E/S é concluída. Para qual estado o processo transita imediatamente?
- a)Executando — a CPU é imediatamente entregue a ele
- b)Terminado — a operação foi concluída
- c)Pronto — ele entra na fila de prontos aguardando a CPU
- d)Novo — o processo é reiniciado
- e)Suspenso — aguarda ser trazido do disco
7. O que distingue um processo 'zumbi' de um processo normal no Linux?
- a)O zumbi está consumindo alta CPU sem produzir resultado útil
- b)O zumbi terminou sua execução mas seu PCB ainda existe porque o pai não coletou seu status com wait()
- c)O zumbi é um processo cujo pai morreu antes dele
- d)O zumbi está bloqueado aguardando um recurso que nunca será liberado
- e)O zumbi é um processo que ficou suspenso por swapping há muito tempo
8. Após fork(), o processo-filho chama execlp(). O que execlp() faz com o espaço de endereçamento do filho?
- a)Cria uma nova cópia do espaço de endereçamento do pai
- b)Compartilha o espaço de endereçamento com o pai usando copy-on-write
- c)Substitui completamente a imagem de memória do filho pelo novo programa
- d)Adiciona o novo programa ao espaço de endereçamento existente do filho
- e)Salva o espaço de endereçamento atual no disco antes de carregar o novo programa
9. Quantos processos são criados pelo seguinte código C (incluindo o processo original)? `fork(); fork();`
- a)1 processo
- b)2 processos
- c)3 processos
- d)4 processos
- e)8 processos
10. Qual é a principal diferença entre processos CPU-bound e I/O-bound, e qual deles tende a ter rajadas de CPU (CPU bursts) mais longas?
- a)CPU-bound faz muitas chamadas de sistema; I/O-bound usa a CPU continuamente por longos períodos
- b)CPU-bound tem rajadas de CPU longas e poucas operações de E/S; I/O-bound tem rajadas curtas e muitas operações de E/S
- c)CPU-bound é sempre mais prioritário que I/O-bound no escalonador
- d)I/O-bound nunca precisa da CPU; CPU-bound nunca usa dispositivos de E/S
- e)A distinção só existe em sistemas batch, não em sistemas de tempo compartilhado
Referências
Principais (essenciais)
- SILBERSCHATZ, A.; GALVIN, P. B.; GAGNE, G. Fundamentos de Sistemas Operacionais. 9. ed. LTC, 2015.
- Seções: 1.4, 1.5, 1.6, 1.7 (contexto de multiprogramação), 2.3, 2.4, 3.1, 3.2, 3.3
Aprofundamento (opcionais)
- TANENBAUM, A. S. Sistemas Operacionais Modernos. 4. ed. Pearson, 2016. Cap. 2 — Processos e Threads.
- STALLINGS, W. Operating Systems: Internals and Design Principles. 9. ed. Pearson, 2018. Cap. 3.
- Linux kernel source —
include/linux/sched.h(estruturatask_struct): elixir.bootlin.com
Recursos Complementares
Opcional — Vídeos selecionados para reforçar os conceitos desta aula.
14:35Process Management (Processes and Threads)
Neso Academy
Introdução ao conceito de processo, diferença entre programa e processo, e modelo de estados. Segue o Capítulo 3 do Silberschatz.
12:06Operating System Basics
Neso Academy
Reforço dos fundamentos de operação do SO (interrupções, modo kernel/usuário e fluxo de execução), base necessária para entender criação e ciclo de vida de processos.
11:43Operating Systems: Crash Course Computer Science #18
CrashCourse
Visão geral clara de processos, escalonamento e responsabilidades do sistema operacional. Útil como revisão rápida antes dos exercícios da aula.
2:11:13Introduction to Operating System | Full Course for Beginners
Mike Murphy Co
Curso mais longo para consolidar processo, PCB, escalonamento e chamadas de sistema em uma trilha contínua de estudo.