163 lines
6.1 KiB
Markdown
163 lines
6.1 KiB
Markdown
# 📐 Algoritmos de Escalonamento
|
|
|
|
Este documento descreve em detalhes os algoritmos de escalonamento implementados no PSS. Para cada algoritmo são apresentados o princípio de funcionamento, parâmetros, regras de desempate e exemplos didáticos.
|
|
|
|
---
|
|
|
|
## Regras Gerais
|
|
|
|
- **Unidade de tempo:** o simulador opera em *ticks* discretos. Cada tick representa 1 unidade de tempo de CPU.
|
|
- **Bursts:** cada processo possui uma sequência de bursts alternados: `CPU → I/O → CPU → ...`, sempre começando com CPU.
|
|
- **Desempate:** quando dois processos estão empatados no critério de seleção do algoritmo, a prioridade vai para o que chegou primeiro (`arrivalTime`). Em segundo desempate, usa-se o `id` em ordem lexicográfica.
|
|
- **Context Switch:** se configurado (≥ 1 tick), um overhead é inserido toda vez que a CPU troca de processo.
|
|
|
|
---
|
|
|
|
## FCFS — First Come, First Served
|
|
|
|
**Tipo:** Não-preemptivo
|
|
|
|
### Como funciona
|
|
|
|
Talvez o algoritmo mais intuitivo: o processo que chegou primeiro é atendido primeiro. A fila Ready é ordenada por `arrivalTime`. Quando um processo ocupa a CPU, ele permanece lá até completar seu burst de CPU atual — sem interrupções.
|
|
|
|
### Exemplo
|
|
|
|
```
|
|
P1: chegada=0, CPU: 4 ticks
|
|
P2: chegada=1, CPU: 3 ticks
|
|
P3: chegada=2, CPU: 1 tick
|
|
|
|
Gantt: | P1 P1 P1 P1 | P2 P2 P2 | P3 |
|
|
Tick: 0 1 2 3 4 5 6 7
|
|
```
|
|
|
|
| Processo | Turnaround | Waiting |
|
|
|----------|:----------:|:-------:|
|
|
| P1 | 4 | 0 |
|
|
| P2 | 6 | 3 |
|
|
| P3 | 6 | 5 |
|
|
|
|
### Observação: Efeito de Comboio
|
|
|
|
Se um processo longo chega antes de vários processos curtos, estes ficam esperando por muito tempo — mesmo que a CPU esteja "disponível" para eles. Este fenômeno é chamado de **Convoy Effect** e é um dos principais problemas do FCFS. Experimente o preset `convoy_effect` para visualizá-lo.
|
|
|
|
---
|
|
|
|
## SJF — Shortest Job First (Não-Preemptivo)
|
|
|
|
**Tipo:** Não-preemptivo
|
|
|
|
### Como funciona
|
|
|
|
Ao selecionar o próximo processo, o SJF escolhe aquele com o **menor burst de CPU restante** na fila Ready. Uma vez na CPU, o processo não é interrompido até completar seu burst.
|
|
|
|
O SJF é ótimo para minimizar o tempo médio de espera, mas tem um problema prático: em sistemas reais, a duração dos bursts futuros é desconhecida. No simulador, você define os bursts explicitamente, então o SJF pode ser aplicado perfeitamente.
|
|
|
|
### Parâmetros
|
|
|
|
Nenhum parâmetro adicional.
|
|
|
|
---
|
|
|
|
## SRTF — Shortest Remaining Time First (SJF Preemptivo)
|
|
|
|
**Tipo:** Preemptivo
|
|
|
|
### Como funciona
|
|
|
|
Versão preemptiva do SJF. A cada tick, o escalonador verifica se algum processo na fila Ready possui tempo de burst restante **menor** que o processo atualmente em execução. Se sim, ocorre uma preempção: o processo atual é devolvido à fila Ready e o novo candidato assume a CPU.
|
|
|
|
### Exemplo
|
|
|
|
```
|
|
P1: chegada=0, CPU: 8 ticks
|
|
P2: chegada=1, CPU: 4 ticks
|
|
|
|
Tick 0: P1 começa (remaining=8)
|
|
Tick 1: P2 chega (remaining=4 < 7) → preempção!
|
|
Tick 5: P2 termina → P1 retoma (remaining=7)
|
|
Tick 12: P1 termina
|
|
```
|
|
|
|
---
|
|
|
|
## Round Robin (RR)
|
|
|
|
**Tipo:** Preemptivo
|
|
**Parâmetro:** `quantum` (fatia de tempo, padrão: 2)
|
|
|
|
### Como funciona
|
|
|
|
A fila Ready é tratada como uma fila circular. Cada processo recebe no máximo `quantum` ticks de CPU consecutivos. Se ao final do quantum o processo ainda tiver burst restante, ele retorna ao **fim** da fila Ready e aguarda sua vez.
|
|
|
|
I/O bursts **não** consomem quantum — o processo sai voluntariamente da CPU quando inicia I/O.
|
|
|
|
### Tradeoff
|
|
|
|
Quanto menor o quantum, mais justo o revezamento, mas maior o overhead de context switches. Quanto maior, o RR se aproxima do FCFS.
|
|
|
|
---
|
|
|
|
## Priority Scheduling (Não-Preemptivo e Preemptivo)
|
|
|
|
**Tipo:** Não-preemptivo ou Preemptivo (selecione no painel)
|
|
**Parâmetros:** Aging (opcional) + intervalo de aging
|
|
|
|
### Como funciona
|
|
|
|
Cada processo tem uma prioridade de `1` (maior) a `10` (menor). O escalonador sempre seleciona o processo de maior prioridade na fila Ready.
|
|
|
|
- **Não-preemptivo:** uma vez na CPU, o processo termina seu burst sem ser interrompido.
|
|
- **Preemptivo:** se um processo de prioridade maior chegar, o atual é preemptado imediatamente.
|
|
|
|
### Starvation e Aging
|
|
|
|
O problema clássico do Priority Scheduling é o **starvation**: processos de baixa prioridade podem *nunca* receber a CPU se processos de alta prioridade chegam continuamente.
|
|
|
|
A solução é o **aging**: a cada `agingInterval` ticks que um processo permanece na fila Ready, sua prioridade é incrementada em 1 (ou seja, o valor numérico diminui), até o mínimo de `1`. Com o tempo, mesmo processos de baixa prioridade chegam à cabeça da fila.
|
|
|
|
Experimente os presets `starvation` e `aging_fix` para ver esta diferença.
|
|
|
|
---
|
|
|
|
## HRRN — Highest Response Ratio Next
|
|
|
|
**Tipo:** Não-preemptivo
|
|
|
|
### Como funciona
|
|
|
|
O HRRN tenta ser mais justo que o SJF levando em conta o tempo de espera do processo. A cada seleção, calcula-se o **Response Ratio** de cada processo na fila:
|
|
|
|
```
|
|
ratio = (waitingTime + burstTime) / burstTime
|
|
```
|
|
|
|
O processo com o **maior ratio** é selecionado. Isso faz com que processos que esperam há muito tempo tenham sua prioridade aumentada naturalmente, evitando starvation.
|
|
|
|
| Situação | Efeito no ratio |
|
|
|----------|----------------|
|
|
| Processo com burst curto | ratio alto desde o início |
|
|
| Processo esperando há muito tempo | ratio cresce com o tempo |
|
|
| Processo com burst longo + pouco wait | ratio baixo |
|
|
|
|
---
|
|
|
|
## Multilevel Queue
|
|
|
|
**Tipo:** Preemptivo
|
|
**Parâmetros:** número de filas, quantum por fila
|
|
|
|
### Como funciona
|
|
|
|
Os processos são distribuídos em múltiplas filas com diferentes prioridades. Cada fila tem seu próprio quantum de Round Robin. Filas de maior prioridade sempre são servidas primeiro — uma fila de menor prioridade só recebe CPU se todas as filas acima dela estiverem vazias.
|
|
|
|
Isso permite tratar diferentes classes de processos de forma distinta: por exemplo, processos interativos em filas de alta prioridade (quantum pequeno) e processos batch em filas de baixa prioridade (quantum maior).
|
|
|
|
---
|
|
|
|
## Referências
|
|
|
|
- Silberschatz, A., Galvin, P. B., & Gagne, G. — *Operating System Concepts*, 10ª edição
|
|
- Tanenbaum, A. S. — *Modern Operating Systems*, 4ª edição
|