Conceito de Processo
Video da aula estara disponivel em breve
Programa vs. Processo
A distincao entre programa e processo e fundamental e frequentemente cobrada em provas:
- Programa: entidade passiva. Um arquivo executavel armazenado no disco. Contem instrucoes e dados, mas nao esta em execucao.
- Processo: entidade ativa. Um programa em execucao, com seu proprio espaco de enderecamento, registradores, pilha, e estado. Existe em memoria.
Um mesmo programa pode ter varios processos simultaneos. Por exemplo, voce pode abrir tres terminais executando bash — sao tres processos distintos do mesmo programa.
Estrutura de um Processo
Cada processo em execucao possui um espaco de enderecamento virtual que tipicamente contem:
Enderecos altos
+---------------------------+
| Stack | ← variaveis locais, enderecos de retorno
| ... | cresce para baixo
| |
| |
| ... |
| Heap | ← alocacao dinamica (malloc/new)
| | cresce para cima
+---------------------------+
| BSS | ← variaveis globais nao inicializadas
+---------------------------+
| Data | ← variaveis globais inicializadas
+---------------------------+
| Text (Code) | ← instrucoes do programa (read-only)
+---------------------------+
Enderecos baixos
Process Control Block (PCB)
O kernel mantem uma estrutura de dados para cada processo chamada PCB (Process Control Block), tambem chamada de task_struct no Linux. Essa estrutura armazena todas as informacoes que o SO precisa para gerenciar o processo:
- PID (Process ID) — identificador unico
- Estado — running, ready, waiting, etc.
- Registradores — valores salvos quando o processo perde a CPU
- Program Counter — endereco da proxima instrucao
- Informacoes de memoria — tabela de paginas, limites
- Informacoes de I/O — arquivos abertos, dispositivos
- Contabilidade — tempo de CPU usado, prioridade
// Versao simplificada de como um PCB pode ser representado
struct pcb {
int pid; // Process ID
int state; // RUNNING, READY, WAITING...
int priority; // prioridade de escalonamento
unsigned long pc; // program counter
unsigned long registers[16]; // registradores salvos
unsigned long stack_ptr; // ponteiro de pilha
struct mm_struct *memory; // info de memoria
struct file *open_files; // arquivos abertos
unsigned long cpu_time; // tempo de CPU usado
};
Criacao de Processos
Em sistemas Unix/Linux, processos sao criados pela system call fork(). O fork() cria uma copia quase identica do processo que o chamou (o pai), produzindo um novo processo (o filho).
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
printf("Processo pai: PID = %d\n", getpid());
pid_t pid = fork();
if (pid < 0) {
// Erro: fork falhou
perror("fork");
return 1;
}
if (pid == 0) {
// Este codigo roda no processo FILHO
printf("Filho: PID = %d, pai = %d\n", getpid(), getppid());
// Tipicamente, o filho chama exec() para rodar outro programa
execlp("ls", "ls", "-la", NULL);
} else {
// Este codigo roda no processo PAI
printf("Pai: esperando filho %d terminar...\n", pid);
wait(NULL); // espera o filho terminar
printf("Pai: filho terminou.\n");
}
return 0;
}
gcc -o fork_demo fork_demo.c e execute. Observe os PIDs impressos. Execute varias vezes — os PIDs mudam a cada execucao.
Hierarquia de Processos
No Linux, todo processo (exceto o primeiro, o init ou systemd com PID 1) tem um processo pai. Isso cria uma arvore de processos que voce pode visualizar com o comando pstree:
# Ver a arvore de processos
$ pstree -p
systemd(1)─┬─sshd(1234)───sshd(5678)───bash(5679)───vim(5680)
├─nginx(2345)─┬─nginx(2346)
│ └─nginx(2347)
└─postgres(3456)─┬─postgres(3457)
└─postgres(3458)
# Ver informacoes de um processo especifico
$ ps aux | grep nginx
# Ver o /proc filesystem (interface do kernel para processos)
$ ls /proc/1/
$ cat /proc/self/status # info do processo atual
Terminacao de Processos
Um processo pode terminar de varias formas:
- Saida normal: o processo termina voluntariamente (retorno de
main()ou chamada aexit()) - Saida por erro: o processo encontra um erro e termina (ex: arquivo nao encontrado)
- Erro fatal: o SO encerra o processo por uma violacao (segmentation fault, divisao por zero)
- Encerramento por outro processo: um processo envia um sinal (ex:
kill -9 PID)
Quando um processo termina, o SO libera todos os seus recursos: memoria, arquivos abertos, locks. O processo pai pode obter o codigo de saida do filho atraves de wait().
wait(), o filho terminado fica como zumbi (zombie) — o PCB permanece na tabela de processos. Se o pai termina antes do filho, o filho fica orfao e e adotado pelo init/systemd (PID 1).
Resumo
- Programa e passivo (arquivo em disco); processo e ativo (programa em execucao)
- Cada processo tem seu espaco de enderecamento (text, data, heap, stack)
- O kernel mantem um PCB para cada processo com todas as informacoes de estado
fork()cria processos;exec()carrega novos programas;wait()sincroniza pai e filho- Processos formam uma hierarquia em arvore no Linux
Verifique seu entendimento
Apos uma chamada fork() bem-sucedida, quantos processos existem e o que cada um recebe como retorno?