Você está na página 1de 38

PONTIFÍCIA UNIVERSIDADE CATÓLICA DE MINAS GERAIS

Campus de Poços de Caldas


Curso de Graduação em Ciência da Computação

LABORATÓRIO DE SISTEMAS
OPERACIONAIS
Escalonador

Dyego Henrique Melo Dias


Professor: Dr. João Carlos de Moraes Morselli Junior

Poços de Caldas
11/06/2010
PONTIFÍCIA UNIVERSIDADE CATÓLICA DE MINAS GERAIS
Campus de Poços de Caldas
Curso de Graduação em Ciência da Computação

LABORATÓRIO DE SISTEMAS
OPERACIONAIS:
Escalonador

Trabalho apresentada à disciplina de


Laboratório de Sistemas Operacionais,
do Curso de Ciência da Computação
como requisito parcial para obtenção
do título de Bacharel em Ciência da
Computação da Pontifícia Universidade
Católica de Minas Gerais.

Dyego Henrique Melo Dias


Professor: Dr. João Carlos de Moraes Morselli Junior

Poços de Caldas
11/06/201

2
Sumário
1.
U U Introdução ................................................................................................................ 5
U U

2.
U U Sistema Operacional ................................................................................................ 6
U U

2.1.
U U System Calls ...................................................................................................... 6
U U

2.2.
U U Processos ........................................................................................................... 6
U U

2.3.
U U Arquivos ............................................................................................................ 7
U U

3.
U U Escalonador de Processos ........................................................................................ 8
U U

3.1.
U U Objetivos do Escalonamento ............................................................................. 8
U U

3.2.
U U Algoritmos Escalonadores ................................................................................. 8
U U

3.2.1.
U U FIFO ........................................................................................................... 9
U U

3.2.2.
U U SJF .............................................................................................................. 9
U U

3.2.3.
U U SRT ............................................................................................................ 9
U U

3.2.4.
U U Algoritmo Loteria ...................................................................................... 9
U U

3.2.5.
U U Escalonamento garantido ........................................................................... 9
U U

3.2.6.
U U RR .............................................................................................................. 9
U U

3.2.7.
U U Múltiplas Filas ............................................................................................ 9
U U

4.
U U Simulação ............................................................................................................... 10
U U

5.
U U Funcionamento ....................................................................................................... 11
U U

6.
U U FILAS ..................................................................................................................... 12
U U

7.
U U Simulações ............................................................................................................. 13
U U

7.1.
U U Simulação 1 ..................................................................................................... 13
U U

7.2.
U U Simulação 2 ..................................................................................................... 14
U U

7.3.
U U Simulação 3 ..................................................................................................... 15
U U

7.4.
U U Simulação 4 ..................................................................................................... 16
U U

8.
U U Comparando ........................................................................................................... 17
U U

8.3.
U U Quantidade total de starvation durante a simulação. ....................................... 18
U U

8.4.
U U Conclusão das Simulações .............................................................................. 19
U U

9.
U U Outras Simulações .................................................................................................. 20
U U

9.1.
U U Simulação 5 ..................................................................................................... 20
U U

9.2.
U U Simulação 6 ..................................................................................................... 21
U U

9.3.
U U Simulação 7 ..................................................................................................... 22
U U

9.4.
U U Simulação 8 ..................................................................................................... 23
U U

10.
U U Média de Throughput .......................................................................................... 24
U U

11.
U U COMPARAÇÃO DAS SIMULAÇÕES 6, 7, 8 e 9 ............................................ 27
U U

11.1.
U U Quantidade total de processos criados durante a simulação. ....................... 27
U U

11.2.
U U Quantidade total de processos executados durante a simulação. ................. 28
U U

11.3.
U U Quantidade total de starvation durante a simulação. ................................... 28
U U

3
13.
U U CONCLUSÃO SIMULAÇÃO 2 ........................................................................ 29
U U

14.
U U Bibliografia ......................................................................................................... 30
U U

15.
U U Anexos ................................................................................................................ 31
U U

15.1.
U U Escalonador.c ............................................................................................... 31
U U

15.2.
U U Bibli.h .......................................................................................................... 34
U U

15.3.
U U Estatistica.txt ................................................................................................ 38
U U

4
1. Introdução

Durante o percorrer do curso, estudamos na matéria de Sistemas


Operacionais os Sistemas Operacionais em si e sua funcionalidades básicas,
será apresentado neste documento uma explicação sobre escalonador
(scheduler) e variáveis que fazem parte de sua implementação e execução.
Também será apresentado apresentada a implementação de um
escalonador básico, e os testes realizados em cada cenário no escalonador
implementado.

5
2. Sistema Operacional

Segundo Tanenbaum & Woodhull em [Sistemas Operacionais, 2000], o


programa de sistemas mais fundamental é o Sistema Operacional, que controla
todos os recursos do computador e fornece a base sobre a qual os programas
aplicativos podem ser escritos.
São os sistemas operacionais que proporcionam uma interface de
iteração para o usuário e o hardware, ele funciona como um intermediador
entre usuário e hardware.
Um Sistema Operacional é dividido em partes para seu funcionamento
ser realizado com sucesso, estas partes são, as System Calls, os Processos,
os Arquivos e o Shell.

2.1. System Calls

System Calls são instruções estendidas que fazem a interface entre o


Sistema Operacional e os Programas de Usuários. Tais Instruções variam de
Sistema Operacional para Sistema Operacional.

2.2. Processos

O conceito mais importante no estudo de sistemas operacionais, é o


conceito de processo. Em um computador multiprogramado, que contem vários
programas executando simultaneamente na memória, corresponde a um
procedimento ou seqüência de instruções e um conjunto de dados variáveis
utilizadas pelo programa. Além das instruções e dados, cada programa em
execução possui uma área de memória correspondente para armazenar os
valores dos registradores da UCP, quando o programa, por algum motivo, não
estiver sendo executado. Essa área de memória é conhecida como registro

6
descritor e, além dos valores dos registradores da UCP, contém outras
informações.
Assim, em um determinado sistema, cada programa em execução
constitui um processo. Portanto, podemos definir processo como sendo um
programa em execução, o qual é constituído por uma seqüência de instruções,
um conjunto de dados e um registro descritor.

2.3. Arquivos

Arquivos são informações contidas em Disco ou dispositivos de I/O,


segundo Tanenbaum & Woodhull em [Sistemas Operacionais, 2000], as
chamadas de sistemas são necessárias para criar, para remover, para ler e
para escrever arquivos. Antes de um arquivo poder ser lido, ele deve ser aberto
e depois de lido deve ser fechado, assim chamadas são fornecidas para tais
coisas. Tais chamadas são interpretadas e executadas pelo Sistema
Operacional, que manipula o disco onde o arquivo e informações presentes
nele estão contidas.

7
3. Escalonador de Processos

Quando um ou mais processos estão prontos para serem executados, o


Sistema Operacional deve decidir qual deles vai ser executado primeiro. A
parte do Sistema Operacional responsável por essa decisão é chamada de
escalonador, e o algoritmo usado para tal é chamado de algoritmo de
escalonamento. Em sistemas multiusuários e de tempo compartilhado o
algoritmo de escalonamento é bem complexo.
O Escalonador de Processos (scheduling), é uma atividade exercida
pelo escalonador, possibilitando assim que se execute mais processos de uma
só vez, onde estes processos são divididos por prioridade, assim os processos
com maior prioridade como os de I/O Bound e os Computacionalmente
intensivos.

3.1. Objetivos do Escalonamento

Justiça: fazer com que cada processo ganhe seu tempo justo, para
usarem o mesmo tempo na CPU;
Eficiência: manter a CPU ocupada a maior parte do tempo;
Tempo de Reposta: minimizar o tempo de resposta para os usuários
interativos;
Tempo de Turnaround: minimizar o tempo que usuários devem esperar
pelo resultado;
Throughput: maximizar o número de tarefas executados por unidade de
tempo.

3.2. Algoritmos Escalonadores

Existem dois tipos de algoritmos de escalonamento os preemptivos e os


não preemptivos, onde os algoritmos preemptivos permitem que os processos
sejam interrompidos durante sua execução e os algoritmos não preemptivos,
por serem utilizados exclusivamente em sistemas monoprocessados.

8
Alguns algoritmos de escalonamento mais utilizados são:

3.2.1. FIFO (First in, First Out) ou FCFS (First come, first served) que
como seu próprio nome já diz, o primeiro que chega será o primeiro
a ser executado;
3.2.2. SJF (Shortest Job First): Onde o menor processo ganhará a CPU
e atrás do mesmo formar uma fila de processos por ordem
crescente de tempo de execução;
3.2.3. SRT (Shortest Remaining Time): Neste algoritmo é escolhido o
processo que possua o menor tempo restante, mesmo que esse
processo chegue à metade de uma operação, se o processo novo
for menor ele será executado primeiro;
3.2.4. Algoritmo Loteria: O Sistema Operacional distribui tokens
(fichas), numerados entre os processos, para o escalonamento é
sorteado um numero aleatório para que o processo ganhe a vez na
CPU, processos com mais tokens têm mais chance de receber
antes a CPU.
3.2.5. Escalonamento garantido: Este algoritmo busca cumprir
promessas de alocação de CPU o mais preciso possível.
3.2.6. RR (Round-Robin): Nesse escalonamento o sistema operacional
possui um timer, chamado de quantum, onde todos os processos
ganham o mesmo valor de quantum para rodarem na CPU. Com
exceção do algoritmo RR e escalonamento garantido, todos os
outros sofrem do problema de Inanição (starvation).
3.2.7. Múltiplas Filas: São usadas várias filas de processos prontos
para executar, cada processo e colocado em uma fila, e cada fila
tem uma política de escalonamento própria e outra entre filas.

9
4. Simulação

Para que seja simulado um escalonador de processos de um sistema


operacional foi desenvolvido um algoritmo em múltiplas filas que durante sua
execução gera informações que são gravadas em um arquivo de estatísticas
para que os resultados obtidos possam ser analisados.
Neste algoritmo levamos em consideração alguns aspectos de
funcionamento de um escalonador verdadeiro, como: tamanho dos processos,
prioridades, quamtum (tempo que o processo recebe de CPU) e starvation
(processos que demoram muito tempo para ganhar a CPU).
Para obter alguns dados relativos ao escalonamento, usamos, neste
mesmo algoritmo, uma estrutura com algumas variáveis que armazenavam
informações para gerar uma estatística de desempenho. Com esses dados
sabemos, por exemplo, quantos processos foram criados e executados por
cada fila de prioridade, podendo assim saber o throughput. Abaixo
mostraremos o funcionamento do algoritmo e o software utilizado para gerar os
gráficos, e a seguir cada etapa da simulação e comentários a respeito dos
testes.

10
5. Funcionamento

O algoritmo aqui comentado, implementa um simulador de um


escalonador de processos, este algoritmo foi desenvolvido na linguagem C.
Neste algoritmo foram implementados estruturas que simulam as propriedades
e atributos de uma CPU e os Processos, filas com faixas crescentes de
prioridade inclusive uma para processo de sistema em tempo real, e algumas
outras funções.
A cada iteração, é chamada uma função que verifica a necessidade de
criar novos processos, esta função atribui um valor randômico a uma variável,
que é comparada a fim de saber se deve ser criado um novo processo ou não.
Caso um novo processo seja criado, é atribuído inicia-se uma nova instancia da
estrutura processo com os atributos de ID, prioridade, tamanho e quantum, que
após sua criação ele é inserido em uma fila de acordo com sua prioridade.
Se não for criado um processo nessa iteração com a CPU, é chamado o
escalonador. Este verifica as filas, para saber em qual fila há processo
esperando por CPU, e executa o processo com prioridade maior. Nesta
execução é dado um quantum, o tempo que o processo pode usar de CPU, e
após a execução, é diminuído o tamanho do processo em relação a este
quantum.
Um processo é considerado como executado quando seu tamanho
quantum é zero, isto significa que ele não precisa mais ser levado à CPU e
pode ser retirado das filas de Processos e realocado de acordo com sua
prioridade.
No final das iterações estipuladas, o algoritmo gera um relatório com os
dados colhidos ante sua execução, e os grava em um arquivo em disco
chamado “estatísticas.txt”.

11
6. FILAS

Usamos a seguinte política para separar os processos por prioridade.

Fila 1: esta fila é usada no caso de chegar algum processo de extrema


importância, por exemplo, de tempo real. Somente é colocado nesta fila
processos com prioridade 0 (zero). Estes processos são executados por inteiro,
sem poder ser retirado da CPU antes de terminar.

Fila 2: processos com prioridade de 1 até 19.

Fila 3: processos com prioridade de 20 até 39.

Fila 4: processos com prioridade de 40 até 59.

Fila 5: processos com prioridade de 60 até 79.

Fila 6: processos com prioridade de 80 até 99.

12
7. Simulações

7.1. Simulação 1

Nesta primeira simulação utilizamos a função rand() para atribuir o


quantum aleatoriamente aos novos processos gerados. Foi feita uma
simulação com probabilidade de 20% de ser criado um processo, em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.

100
90
80
70
60
Processos criados
50
processos executados
40
starvattion
30
20
10
0
0 500 1000 1500 2000

Verificamos que com esta probabilidade de criar novos processos, o


escalonador executou todos processos gerados.

13
7.2. Simulação 2

Nesta segunda simulação continuamos utilizando a função rand() para


atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 20 para 40% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.

100
90
80
70
60
Processos criados
50
processos executados
40
30 starvattion

20
10
0
0 500 1000 1500 2000

Com esta probabilidade de criar processos, o escalonador já não


conseguiu executar a totalidade dos processos. Reparamos também que na
última faixa de tempo, o escalonador executou mais processos, isso por que a
criação de novos processos diminuiu, conseqüentemente diminuindo os
processos em starvation e aumentado um pouco o throughput.

14
7.3. Simulação 3

Nesta terceira simulação continuamos utilizando a função rand() para


atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 40 para 60% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.

100
90
80
70
60
Processos criados
50
processos executados
40
starvattion
30
20
10
0
0 500 1000 1500 2000

Com 60% de probabilidade de criar novos processos, o escalonador não


conseguiu executar muitos processos, tendo uma queda considerável de
rendimento. Até a terceira faixa de tempo percebemos que o starvation
aumentou progressivamente e após passar das 1500 interações ocorreu uma
queda acentuada do mesmo.

15
7.4. Simulação 4

Nesta quarta simulação continuamos utilizando a função rand() para


atribuir o quantum aleatoriamente aos novos processos gerados, mas
alteramos a probabilidade de criar processos de 60 para 80% em 2000
iterações do sistema. Pegamos informações em 4 faixas de tempo que são: 0-
499, 500-999, 1000-1499 e 1500-1999 iterações.

100
90
80
70
60
Processos criados
50
processos executados
40
starvattion
30
20
10
0
0 500 1000 1500 2000

Ao aumentar a probabilidade de criar novos processos de 60% para


80%, ouve um aumento no numero de processos criados, mas, o desempenho
continuou caindo, pois o numero de processos executados é quase
desprezível. Em relação ao Starvation não tivemos muitas alterações. Até a
terceira faixa de tempo percebemos que o starvation aumentou
progressivamente e após passar das 1500 interações ocorreu uma queda
acentuada do mesmo.

16
8. Comparando

Vamos mostrar alguns gráficos com as comparações de processos


criados, executados, throughput, e starvation com a criação em quantidade
baixa, média e grande de novos processos.

Iterações = 2000

Quantum = randômico

Probabilidade de criar novo processo = 20%, 40%, 60% 80%

8.1. Quantidade total de processos criados durante a simulação:

100
90
80
70
60 Processos criados
50 processos executados
40 starvattion
30 #REF!
20
10
0
0 500 1000 1500 2000

17
8.2. Quantidade total de processos executados durante a
simulação.

800

700

600

500
Processos criados
400 processos executados
300 starvattion
#REF!
200

100

0
0 500 1000 1500 2000

8.3. Quantidade total de starvation durante a simulação.

800

700

600

500
Processos criados
400 processos executados
300 starvattion
#REF!
200

100

0
0 500 1000 1500 2000

Como podemos observar no segundo gráfico, o número de processos


executados não aumentou muito em relação a mudança de quantidade de
processos novos, apesar do número de novos processos ter aumentado

18
significativamente, como observamos no primeiro gráfico. Em relação ao
starvation, podemos ver que o aumento de starvation foi proporcional ao
aumento de novos processos.

8.4. Conclusão das Simulações

Analisando os gráficos, chegamos a conclusão que atribuindo um


quantum aleatoriamente aos processos que serão executados, o desempenho
do escalonador só é aceitável quando o número de novos processos chegando
a CPU é baixo.

Quanto mais processos chegam a CPU em um curto espaço de tempo,


menos processos são executados, especialmente quando têm prioridade
menor, já que os processos com prioridade maior, ainda tem uma boa
porcentagem de execução.

19
9. Outras Simulações
Nas próximas simulações (6, 7, 8 e 9) atribuímos o quantum aos novos
processos de forma diferente. Pegamos o tamanho do processo que está
chegando a CPU e dividimos por dois. O resultado será utilizado como
quantum para a execução. Foram feitas simulações com probabilidades de
20%, 40%, 60% e 80% de ser criado um processo, em 2000 iterações do
sistema. Pegamos informações em 4 faixas de tempo que são: 0-499, 500-999,
1000-1499 e 1500-1999 iterações.

9.1. Simulação 5

Iterações = 2000

Quantum = tamanho / 2

Probabilidade de criar novo processo = 20%

100
90
80
70
60
Processos criados
50
processos executados
40
starvattion
30
20
10
0
0 500 1000 1500 2000

Verificamos que com esta probabilidade de criar novos processos, o


escalonador executou todos. Somente na terceira faixa de tempo, ficaram
alguns sem executar, o que foi compensado na parte final.

20
9.2. Simulação 6

Iterações = 2000

Quantum = tamanho / 2

Probabilidade de criar novo processo = 40%

800

700

600

500
Processos criados
400
processos executados
300
starvattion
200

100

0
0 500 1000 1500 2000

Com esta probabilidade de criar processos, o escalonador continuou


executando um bom número de processos. Na terceira faixa de tempo teve um
aumento de processos novos, o que acarretou uma queda de throughput, e
aumento do starvation.

Como na parte final, a criação de processos foi maior, o escalonador


diminuiu a execução de processos.

21
9.3. Simulação 7

Iterações = 2000

Quantum = tamanho / 2

Probabilidade de criar novo processo = 60%

800

700

600

500
Processos criados
400
processos executados
300
starvattion
200

100

0
0 500 1000 1500 2000

Com muitos processos precisando utilizar a CPU, o escalonador não


conseguiu executar muitas vezes. Pelo gráfico percebemos que a execução se
manteve constante praticamente todo tempo, mesmo tendo uma pequena
variação na quantidade de processos criados.

22
9.4. Simulação 8

Iterações = 2000

Quantum = tamanho / 2

Probabilidade de criar novo processo = 80%

1400

1200

1000

800 Processos criados


600 processos executados
starvattion
400

200

0
0 500 1000 1500 2000

Os gráficos indicam que com a criação de processos em 80% A CPU


não modificou muito a sua forma de execução, ficando muito parecido com o
gráfico de 60% de probabilidade, tendo apenas um aumento no starvation e
uma queda dos processos executados.

23
10. Média de Throughput

As médias de throughput foram calculadas a partir de cada interação


executada, visando assim mostrar em cada interação a quantidade de
processos executados.
Foram feitas quatro interações, onde sua duração é determinada por um
loop de 500 voltas, de onde foram tirados os dados dos processos executados
por fase de interação que seria a unidade de tempo necessária para calcular o
throughput.

Fila 1
70
60
50
40
30 Fila 1
20
10
0
500 1000 1500 2000

Fila 2
25

20

15

10 Fila 2

0
500 1000 1500 2000

24
Fila 3
140
120
100
80
60 Fila 3
40
20
0
500 1000 1500 2000

Fila 4
140
120
100
80
60 Fila 4
40
20
0
500 1000 1500 2000

Fila 5
200

150

100
Fila 5
50

0
500 1000 1500 2000

25
Fila 6
160
140
120
100
80
60 Fila 6
40
20
0
500 1000 1500 2000

Para todas as médias de throughput calculadas, foram obtidos seis


gráficos que demonstram o crescimento dos processos executados a cada
faixa de tempo interações que foram realizados. Assim mostro abaixo um
gráfico com um comparativo entre o crescimento do throughput para cada fila.

180
160
140
Fila 1
120
Fila 2
100
Fila 3
80
Fila 4
60
Fila 5
40
Fila 6
20
0
500 1000 1500 2000

Para cada fila tem-se um diferencial de crescimento devido à adição do


tempo quantum para cada fila de acordo com sua prioridade, assim mostrando
um crescimento variado para cada fila.

26
11. COMPARAÇÃO DAS SIMULAÇÕES 6, 7, 8 e 9

Iterações = 12000

Quantum = tamanho / 2

Probabilidade de criar novo processo = 20%, 40%, 60% e 80%

Vamos mostrar alguns gráficos com as comparações de processos


criados, executados e starvation com a criação em quantidade baixa, média e
alta de novos processos.

11.1. Quantidade total de processos criados durante a


simulação.

500
450
400
350
300 20%
250 40%
200 60%
150 80%
100
50
0
0 500 1000 1500 2000

27
11.2. Quantidade total de processos executados durante a
simulação.

100
90
80
70
60 20%
50 40%
40 60%
30 80%
20
10
0
0 500 1000 1500 2000

11.3. Quantidade total de starvation durante a simulação.

1400

1200

1000

800 20%
40%
600
60%
400 80%

200

0
0 500 1000 1500 2000

Como podemos observar pelos gráficos, o número de processos


executados com probabilidade menor de criação de novos processos em
relação ao tempo, é igual a quantidade de processos criados, gerando um bom
throughput. Quando aumentamos a quantidade de processos, o número fica
bem abaixo, o que gera um aumento no starvation.

28
12. CONCLUSÃO SIMULAÇÃO 2

Analisando os gráficos observamos que o número de processos executados que


possuem uma prioridade maior foi satisfatória. Em compensação, processos com
prioridades muito baixa, praticamente não foram a CPU. somente quando tem poucos
processos chegando ao mesmo tempo, estes conseguem acesso a CPU para serem
executados.

Como a quantidade de processos utilizada na terceira fase da simulação foi


elevada, é compreensível o escalonador ter agido desta maneira, por ter dado
preferência à execução dos processos mais importantes. Nas simulações que geraram
uma quantidade razoável de processos, tanto processos com prioridade maior, como
processos com prioridade menor foram executados em bom número. Conseguimos um
bom throughput.

13. CONCLUSÃO SIMULAÇÃO 2

Analisando os gráficos observamos que o número de processos executados que


possuem uma prioridade maior foi satisfatória. Em compensação, processos com
prioridades muito baixa, praticamente não foram a CPU. somente quando tem poucos
processos chegando ao mesmo tempo, estes conseguem acesso a CPU para serem
executados.

Como a quantidade de processos utilizada na terceira fase da simulação foi


elevada, é compreensível o escalonador ter agido desta maneira, por ter dado
preferência à execução dos processos mais importantes. Nas simulações que geraram
uma quantidade razoável de processos, tanto processos com prioridade maior, como
processos com prioridade menor foram executados em bom número. Conseguimos um
bom throughput.

29
14. Bibliografia

TANENBAUM, ANDREW S. – Sistemas Operacionais: projeto e implementação


/ Andrew S. Tanenbaum e Albert S. Woodhull; trad: Edson Furmankiewicz. – 2ª
Edição, Porto Alegre: Bookman, 2000. ISBN 85-7307-530-9.

ESCALONAMENTO DE PROCESSOS, http://pt.wikipedia.org/wiki/


U

Escalonamento_de_processos - Esta página foi modificada pela última vez às


U

00h43min de 11 de maio de 2010.

30
15. Anexos

15.1. Escalonador.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "bibli.h"

main(){
int i, j, x, iteracao=0;
lista Lista1Processos, Lista2Processos, Lista3Processos;
lista Lista4Processos, Lista5Processos, Lista6Processos;
c.tempo = 0;

ARQ = fopen("estatisticas.txt","w");

create(&Lista1Processos);
create(&Lista2Processos);
create(&Lista3Processos);
create(&Lista4Processos);
create(&Lista5Processos);
create(&Lista6Processos);

for (i=0; i<6; i++){


for (j=0; j<4; j++){
e[i][j].cont_proc_novos = 0;
e[i][j].cont_proc_executados = 0;
e[i][j].cont_proc = 0;
e[i][j].cont_proc_starvation = 0;
}
}

while (iteracao < 2000) {


// verifica se foi criado um novo processo. caso criou, coloca
na fila correta
if (cria_processo(iteracao)) {
if (p.prioridade == 0) {
insert(&Lista1Processos, p);
atualiza_estatistica(1, 1, iteracao);
}
else if ((p.prioridade >= 1) && (p.prioridade <= 19))
{
insert(&Lista2Processos,p);
atualiza_estatistica(1, 2, iteracao);
}
else if ((p.prioridade >= 20) && (p.prioridade
<= 39)) {
insert(&Lista3Processos, p);
atualiza_estatistica(1, 3, iteracao);
}
else if ((p.prioridade >= 40) && (p.prioridade <=
59)){
insert(&Lista4Processos, p);
atualiza_estatistica(1, 4, iteracao);
}

31
else if ((p.prioridade >= 60) && (p.prioridade <=
79)){
insert(&Lista5Processos, p);
atualiza_estatistica(1, 5, iteracao);
}
else if ((p.prioridade >= 80) && (p.prioridade <=
99)){
insert(&Lista6Processos, p);
atualiza_estatistica(1, 6, iteracao);
}
}
// caso não tenha sido criado novo processo, simula
execução de um processo
else {
if (!isEmpty(Lista1Processos)){
if (executa_processo(&Lista1Processos))
insert(&Lista1Processos, p);
else atualiza_estatistica(2, 1, iteracao);
}
else if (!isEmpty(Lista2Processos)){
if (executa_processo(&Lista2Processos))
insert(&Lista2Processos, p);
else atualiza_estatistica(2, 2, iteracao);
}
else if (!isEmpty(Lista3Processos)){
if (executa_processo(&Lista3Processos))
insert(&Lista3Processos, p);
else atualiza_estatistica(2, 3, iteracao);
}
else if (!isEmpty(Lista4Processos)){
if (executa_processo(&Lista4Processos))
insert(&Lista4Processos, p);
else atualiza_estatistica(2, 4, iteracao);
}
else if (!isEmpty(Lista5Processos)){
if (executa_processo(&Lista5Processos))
insert(&Lista5Processos, p);
else atualiza_estatistica(2, 5, iteracao);
}
else if (!isEmpty(Lista6Processos)){
if (executa_processo(&Lista6Processos))
insert(&Lista6Processos, p);
else atualiza_estatistica(2, 6, iteracao);
}
}

fprintf(ARQ,"Iteracoes: %d\t", iteracao);


fprintf(ARQ,"Processos criados: %d\t",
e[0][0].cont_proc_novos);
fprintf(ARQ,"Processos executados: %d\n",
e[0][0].cont_proc_executados);

// verifica quantos processos tem em cada fila e se há


starvation
if (iteracao == 499){
verifica_starvation(Lista1Processos, 1, 1);
verifica_starvation(Lista2Processos, 2, 1);
verifica_starvation(Lista3Processos, 3, 1);
verifica_starvation(Lista4Processos, 4, 1);
verifica_starvation(Lista5Processos, 5, 1);
verifica_starvation(Lista6Processos, 6, 1);

32
}
else if (iteracao == 999){
verifica_starvation(Lista1Processos, 1, 2);
verifica_starvation(Lista2Processos, 2, 2);
verifica_starvation(Lista3Processos, 3, 2);
verifica_starvation(Lista4Processos, 4, 2);
verifica_starvation(Lista5Processos, 5, 2);
verifica_starvation(Lista6Processos, 6, 2);
}
else if (iteracao == 1449){
verifica_starvation(Lista1Processos, 1, 3);
verifica_starvation(Lista2Processos, 2, 3);
verifica_starvation(Lista3Processos, 3, 3);
verifica_starvation(Lista4Processos, 4, 3);
verifica_starvation(Lista5Processos, 5, 3);
verifica_starvation(Lista6Processos, 6, 3);
}
else if (iteracao == 2000){
verifica_starvation(Lista1Processos, 1, 4);
verifica_starvation(Lista2Processos, 2, 4);
verifica_starvation(Lista3Processos, 3, 4);
verifica_starvation(Lista4Processos, 4, 4);
verifica_starvation(Lista5Processos, 5, 4);
verifica_starvation(Lista6Processos, 6, 4);

// para armazenar o total


e[0][0].cont_proc = e[0][4].cont_proc;
e[0][0].cont_proc_starvation =
e[0][4].cont_proc_starvation;
}
iteracao++;
}

fprintf(ARQ,"::::::::: FILA 1 ::::::::::\n");


imprime(Lista1Processos);

fprintf(ARQ,"::::::::: FILA 2 ::::::::::\n");


imprime(Lista2Processos);

fprintf(ARQ,"::::::::: FILA 3 ::::::::::\n");


imprime(Lista3Processos);

fprintf(ARQ,"::::::::: FILA 4 ::::::::::\n");


imprime(Lista4Processos);

fprintf(ARQ,"::::::::: FILA 5 ::::::::::\n");


imprime(Lista5Processos);

fprintf(ARQ,"::::::::: FILA 6 ::::::::::\n");


imprime(Lista6Processos);

fprintf(ARQ,"Processos criados: %d", e[0][0].cont_proc_novos);


fprintf(ARQ,"\nProcessos executados: %d",
e[0][0].cont_proc_executados);

mostra_estatistica();

printf("Arquivo com as informações de execução foi gravado


em disco!\n");

33
fclose(ARQ);

} // fim do main

15.2. Bibli.h

#define TRUE 1
#define FALSE 0

typedef struct{
int id;
int prioridade;
int tamanho;
int tamanho_restante;
int quantum;
}processo;

typedef struct{
int id;
int tempo;
}cpu;

typedef struct{
int cont_proc_novos;
int cont_proc_executados;
int cont_proc;
int cont_proc_starvation;
}estatistica;

processo p;
cpu c;
estatistica e[7][5];
FILE *ARQ;

struct no{
processo dado;
struct no *prox;
};

typedef struct
{
struct no *inicio;
} lista;

void create(lista *q){


q->inicio=NULL;
}

int isEmpty(lista q){


if (q.inicio==NULL)
return TRUE;
else
return FALSE;
}

34
int cria_processo(int iteracoes){
int x;
srand(time(NULL) * (e[0][0].cont_proc_novos + 1 * iteracoes +
1));
x = rand()%100;
if (x < 80){
p.id = e[0][0].cont_proc_novos + 1;
p.prioridade = rand()%100;
p.tamanho = 1 + rand()%9;
p.tamanho_restante = p.tamanho;
p.quantum = p.tamanho / 2;
return(TRUE);
}
return(FALSE);
}

int insert(lista *q, processo d){


struct no *aux, *atual, *anterior;
aux = (struct no *) malloc(sizeof(struct no));

if (aux!=NULL){
aux->dado=d; aux->prox=NULL;
anterior = NULL; atual = q->inicio;

while ((atual != NULL) && (d.prioridade > atual-


>dado.prioridade)){
anterior = atual;
atual = atual->prox;
}

if (anterior == NULL){
aux->prox = q->inicio;
q->inicio = aux;
}
else {
anterior->prox=aux;
aux->prox = atual;
}
}
}

int executa_processo(lista *q){


struct no *aux, *atual, *anterior;
srand(time(NULL) * (e[0][0].cont_proc_novos + 1 * (q->inicio)-
>dado.tamanho));

// atribui um quantum ao processo e diminui o tamanho restante


if ((q->inicio)->dado.prioridade == 0)
(q->inicio)->dado.quantum = (q->inicio)->dado.tamanho;
else (q->inicio)->dado.quantum = 1 + rand()%(q->inicio)-
>dado.tamanho;
(q->inicio)->dado.tamanho_restante = (q->inicio)-
>dado.tamanho_restante - (q->inicio)->dado.quantum;
c.tempo = c.tempo + (q->inicio)->dado.quantum;
if ((q->inicio)->dado.tamanho_restante <= 0){
aux = q->inicio;
q->inicio = (q->inicio)->prox;
free(aux);
return(FALSE);
}
else{

35
// guarda os dados do processo atual
p.id = (q->inicio)->dado.id;
p.prioridade = (q->inicio)->dado.prioridade;
p.tamanho = (q->inicio)->dado.tamanho;
p.tamanho_restante = (q->inicio)->dado.tamanho_restante;
p.quantum = (q->inicio)->dado.quantum;

// deleta ele da lista para recolocá-lo


aux = q->inicio;
q->inicio = (q->inicio)->prox;
free(aux);
return(TRUE);
}
}

void verifica_starvation(lista q, int f, int i){


struct no *aux;
aux = q.inicio;

if (!isEmpty(q)){
while (aux != NULL){
e[0][i].cont_proc++;
e[f][i].cont_proc++;

if (aux->dado.tamanho == aux->dado.tamanho_restante){
e[0][i].cont_proc_starvation++;
e[f][i].cont_proc_starvation++;
}
aux = aux->prox;
}
}
}

void imprime(lista q){


struct no *aux;
int ContadorNos = 0;

aux = q.inicio;
if (!isEmpty(q)){
while (aux != NULL){
ContadorNos++;
fprintf(ARQ,"ID: %d", aux->dado.id);
fprintf(ARQ,"\tTamanho: %d", aux->dado.tamanho);
fprintf(ARQ,"\tRestante: %d", aux-
>dado.tamanho_restante);
fprintf(ARQ,"\tQuantum: %d", aux->dado.quantum);
fprintf(ARQ,"\tPrioridade: %d\n", aux-
>dado.prioridade);
aux = aux->prox;
}
fprintf(ARQ,"\n\nQuantidade de processos: %d",
ContadorNos);
}
fprintf(ARQ,"\n\n\n");
}

void atualiza_estatistica(int tipo, int fila, int interacoes){


if (tipo == 1){
e[0][0].cont_proc_novos++;
e[fila][0].cont_proc_novos++;

36
if (interacoes <= 499){
e[0][1].cont_proc_novos++;
e[fila][1].cont_proc_novos++;
}
else if ((interacoes >= 500) && (interacoes <= 999)){
e[0][2].cont_proc_novos++;
e[fila][2].cont_proc_novos++;
}
else if ((interacoes >= 1000) && (interacoes <= 1499)){
e[0][3].cont_proc_novos++;
e[fila][3].cont_proc_novos++;
}
else if ((interacoes >= 1500) && (interacoes <= 1999)){
e[0][4].cont_proc_novos++;
e[fila][4].cont_proc_novos++;
}
}
else if (tipo == 2){
e[0][0].cont_proc_executados++;
- 42 -
e[fila][0].cont_proc_executados++;

if (interacoes <= 499){


e[0][1].cont_proc_executados++;
e[fila][1].cont_proc_executados++;
}
else if ((interacoes >= 500) && (interacoes <= 999)){
e[0][2].cont_proc_executados++;
e[fila][2].cont_proc_executados++;
}
else if ((interacoes >= 1000) && (interacoes <= 1499)){
e[0][3].cont_proc_executados++;
e[fila][3].cont_proc_executados++;
}
else if ((interacoes >= 1500) && (interacoes <= 1999)){
e[0][4].cont_proc_executados++;
e[fila][4].cont_proc_executados++;
}
}
}

void mostra_estatistica(){

int i;
int j;
int faixa = 499;

fprintf(ARQ,"\n_________________________________________________
______________\n\n");
fprintf(ARQ,"ESTATISTICAS");
fprintf(ARQ,"\n_________________________________________________
______________\n\n");

for(i=0;i<5;i++){

if(i==0) fprintf(ARQ,"GERAL\n");
else fprintf(ARQ," FAIXA %d (%d a %d)\n",i,faixa-
499,faixa);

fprintf(ARQ,"Fila\tProcessos Criados\tProcessos
Executados\tQtd Processos\tStarvation\n");

37
for(j=1;j<7;j++){
fprintf(ARQ," %d\t\t%2d\t\t\t%2d\t\t %2d\t %2d\n",j,
e[j][i].cont_proc_novos,
e[j][i].cont_proc_executados,
e[j][i].cont_proc,
e[j][i].cont_proc_starvation);
}
if(j>6) fprintf(ARQ, " T\t\t%2d\t\t\t%2d\t\t %2d\t %2d\n",
e[0][i].cont_proc_novos,
e[0][i].cont_proc_executados,
e[0][i].cont_proc,
e[0][i].cont_proc_starvation);

fprintf(ARQ,"\n_________________________________________________
_________________");
fprintf(ARQ,"\n\n");
faixa += 500;
}
}

15.3. Estatistica.txt

Devido ao grande número de linhas geradas pelo escalonador, estarei


disponibilizando o arquivo na URL seguinte:
http:\\www.comp.pucpcaldas.br/~al550316968/estatísticas.txt

38