Um Estudo Baseado na Visão de Silberschatz sobre
a Complexidade dos Sistemas Operacionais
Jonathan Luís Hackenhaar
Faculdade Cenecista de Osório (FACOS)
Rua 24 de maio, 141 – 95.520-000 – Osório – RS – Brasil
[email protected]
Resumo. O presente artigo tem como objetivo falar sobre o funcionamento dos
Sistemas Operacionais modernos, descrevendo a forma como esse software
atua fazendo a ligação entre o hardware e o usuário que o utiliza, partindo dos
pressupostos desenvolvidos por Abraham Silberschatz que introduz aos Sistemas
Operacionais uma abordagem didática para melhor entendimento de sua
complexidade.
Palavras-chave: Sistemas operacionais, Abraham Silberchatz, Abordagem
didática
1. Introdução
Os sistemas operacionais foram desenvolvidos inicialmente para tentar escalonar as
atividades do sistema de computação, garantindo o bom funcionamento deste e em segundo
lugar para fazer uma interação entre usuário e o ambiente computacional sendo possível
realizar a execução de programas.
No inicio os sistemas operacionais eram usados como console principal, com o
passar do tempo ele foi sendo incrementado por outros programas que melhoraram a
conveniência de programação do sistema, porém em contra ponto exigiam determinado
tempo em sua configuração. A fim de melhorar e aperfeiçoar esse tempo desperdiçado, o
sistema operacional recebeu lots com jobs semelhantes.
O Sistema Operacional é um programa que funciona como ponte entre o hardware
e o usuário do computador. O seu funcionamento facilita a vida do usuário em função da
interface que ele disponibiliza dando conveniência à utilização dos programas e
gerenciamento da máquina com o objetivo de usar o hardware de forma eficiente. Eles
podem ser divididos em hardware, CPU, memória, e dispositivos de entrada e saída
(I/O). Ele fica responsável por gerenciar o funcionamento de todos esses componentes,
dessa forma podemos destacar como um dos objetivos desse sistema coordenar o uso do
hardware entre os usuários e os aplicativos que são executados. Também compõe parte
dessa estrutura que envolve o Sistema Operacional os programas (aplicativos) e os usuários,
que podem ser pessoas e outras máquinas.
Os sistemas de computadores pessoais, que foram adaptados dando prioridade ao
uso e conveniência, que se beneficiaram da forma de desenvolvimento dos sistemas
operacionais de mainframes, exemplo Windows e Linux. Os sistemas paralelos que
utilizam multiprocessadores, compartilhando o barramento têm como vantagem uma maior
produção (thoughput).
Nos sistemas em rede, que fornecem recursos como o
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 32
compartilhamento de arquivos e uma metodologia diferenciada, que permite a troca de
mensagem e processos em computadores diferentes, e os sistemas operacionais distribuídos
que são aqueles em que cada processador tem a sua memória local e se comunicam por
barramentos ou linhas telefônicas.
Os sistemas operacionais existem porque é uma forma razoável de resolver o
problema de criar um sistema de computação que possa ser usado. O objetivo primordial
dos sistemas de computação é executar programas de usuário e tornar fácil a resolução dos
problemas de usuário. Para atingir essa meta, o hardware é construído. Como o hardware
por si só não é particularmente fácil de usar, programas aplicativos são desenvolvidos.
Esses vários programas exigem certas operações comuns, como aquelas que controlam os
dispositivos de I/O. As funções comuns de controle e alocação de recursos são então
reunidas em um único software: o sistema operacional.
O artigo está estruturado da seguinte forma: na seção dois o tema de discussão é
sobre as estruturas de sistemas operacionais, já na seção três a temática é processos, na
seção quatro o assunto exposto é sobre as threads, o escalonamento de CPU é o tema da
seção cinco, na seção seis a sincronização de processos será agregado ao estudo do artigo,
já na seção sete o assunto abordado é sobre deadlocks, a seção oito é responsável pela
gerência de memória, a memória virtual é o assunto da seção nove e a seção dez fala sobre
o sistema de arquivos encerrando com as conclusões.
2. Estruturas de Sistemas Operacionais
O sistema operacional tem como objetivo oferecer um conjunto de funções que são úteis ao
usuário, que a interface com o usuário, a execução de programas, operações de entrada e
saída, manipulação de sistema de arquivos, comunicação entre os componentes,
detecção de erros, depuração (para aumentar a eficiência) alocação de recursos,
contabilização, proteção e segurança de todos os seus componentes.
Um dos recursos mais visíveis e utilizados em sistema operacional é a interface
com o usuário, dessa forma as tarefas começam a serem feitas com a interação do mesmo,
que, por exemplo, pode ser feita por linha de comando. Essa interface pode ser gráfica,
amigável ou ambas simultaneamente (GUI e CLI).
O sistema operacional se comunica através de chamadas de sistema, que geralmente
são escritas em linguagens de alto nível, como C++, por exemplo. Essas chamadas são
usadas para que as tarefas solicitadas ao sistema operacional pelo usuário e softwares
possam ser feitas. A implementação das chamadas de sistema acontece quando a sua
interface evoca ao kernel do sistema e retorna o status e os valores de retorno, as
chamadas de sistemas podem ser de vários tipos, tais como: controle de processos,
gerenciamento de arquivos e dispositivos, manutenção de informações, comunicação e
proteção.
Dentro dessa estrutura temos alguns programas (as interfaces de usuário) que
propiciam um ambiente conveniente para a execução de programas que acabam por
compor a visão do usuário do sistema operacional. Esses programas permitem o
gerenciamento de arquivos, modificação, suporta linguagem de programação, permite
comunicação tornando o sistema operacional útil ao usuário.
O projeto de implementação de um sistema operacional deve estar em equilíbrio
com os objetivos do usuário e os objetivos do próprio sistema, ele deve ser fácil de
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 33
projetar, flexível, confiável e eficiente levando em conta a política e o mecanismo
envolvidos nesse processo.
O sistema operacional se divide em duas estruturas: Estruturas simples – nesse
tipo de estrutura relação de custo-benefício baseado em menor espaço é priorizada, como
por exemplo, nos
sistemas monolíticos, sua estrutura, interface e níveis de
funcionalidade não são bem separados (exemplo MS-DOS). Estrutura em camadas – nesse
contexto o sistema operacional é dividido em camadas (níveis), onde cada uma é constituída
respeitando a hierarquia das camadas, a camada inferior é o hardware e a camada mais alta
é a interface com o usuário, é projetado para que cada uma use as funções e serviços
somente das camadas de baixo nível, como mostrado na Figura 1, que exemplifica a estrutura
em questão.
Figura 1. Modelo de Estrutura em Camadas (MS-DOS)
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
Temos também a Estrutura Microkernel – move o kernel para o espaço do usuário
e a comunicação ocorre entre módulos em nível de usuário usando a troca de
mensagens. Possui vantagens tais como se adaptar em novas arquiteturas e é mais seguro,
porém sobrecarrega em função da comunicação entre o modo usuário e o modo kernel. E
finalizando com a estrutura em Módulos – cada módulo (no kernel) é responsável se
comunica através de interfaces e o módulo é carregado no kernel quando necessário.
As máquinas virtuais nos levam a abordagem de sistemas em camadas ao extremo,
tratando o hardware e o kernel como se ambos fossem hardware. Elas fornecem uma
interface idêntica a do puro hardware, criando a ilusão de múltiplos processos cada um
executando em seu próprio processador com sua própria memória (virtual). Elas são boas
para testes, desenvolvimento e não ocupam espaço demasiado, em alguns casos permitem o
compartilhamento de arquivos (controlados), mas que facilitam muito a vida de quem as
utiliza.
O sistema operacional também conta com a depuração, que é responsável por
encontrar e corrigir erros, gerando logs que contém informações desses erros, por
exemplo, a falha de um programa pode capturar a memória do processo e falhas no
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 34
sistema operacional que podem consumir memória do kernel, além de travamentos.
Depurar é algo duas vezes mais difícil que escrever códigos pela primeira vez, entretanto,
se tu escreves o código tão inteligente quanto possível, tu não és, por definição, inteligente
suficiente para depurá-lo.
Os sistemas operacionais são projetados para executar em qualquer máquina de uma
determinada classe. O sistema operacional conta com alguns programas que o ajudam em
algumas tarefas, tais como: SYSGEM – obtém informações a respeito da configuração
específica do hardware. BOOTING – inicia o computador carregando o kernel.
BOOTSTRAP program – código armazenado em memória ROM que localiza o kernel e
carrega-o na memória para iniciar a sua execução. Dessa forma o sistema operacional é
carregado e começa o seu funcionamento, através do boot.
3. Processos
Um processo é uma fatia de programa que está executando, ele executa uma variedade de
programas, como os sistemas batch e os sistemas de time sharing. O processo progride
em sua execução de maneira sequencial, incluindo um contador, uma pilha e uma seção
de dados. Durante a sua execução sofre alterações de seu estado, que pode ser: Novo –
quando o processo está sendo criado. Executando – quando ele está executando as suas
instruções. Esperando – quando está a espera de algum evento acontecer. Pronto – quando
o processo está esperando ser associado a algum processador e Terminado – quando o
processo termina sua execução, como mostra a Figura 2 abaixo.
Figura 2. Diagrama de Estados do Processo
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
A Figura 3 encarrega-se de expor os dados que são armazenados pelo PCB –
Process Control Block, que carrega as informações associadas com cada processo, como o
seu estado, contador de programa, número ID, registradores de CPU, informações de
escalonamento da CPU, informações do gerenciamento de memória, contabilidade e o status
de E/S.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 35
Figura 3. PCB – Process Control Block
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
Como são muitos os processos que sempre estão querendo executar e assim dar
continuidade as suas instruções, surgiu a necessidade de ter o escalonamento de
processos. O escalonamento de processos pode ser em fila de jobs, que é o conjunto de
todos os processos do sistema, fila de processos prontos, que é o conjunto de todos os
processos residentes na memória principal prontos e esperando para executar e a fila de
dispositivos, quando há um conjunto de processos esperando por um dispositivo de E/S,
ressalvando que devido ao seu estado, o processo pode migrar entre as várias filas de
execução.
Quando temos qualquer tipo de escalonamento, esse deve ser gerenciado pelo
escalonador, no caso dos processos podemos contar com dois escalonadores: o de longo
prazo (ou escalonador de jobs) que seleciona qual processo deve ser executado e aloca a
CPU para ele. A CPU, quando alterna para o outro processo, faz com que o sistema salve
o estado do processo anteriormente salvo do processo novo via troca de contexto, que é
representado na PCB.
Um processo pode criar outro processo (pai-filho), formando uma árvore de
processos. Na relação pai-filho todos os recursos são compartilhados, porém, o filho
compartilha um subconjunto dos recursos do pai, na execução os dois (pai e filho) executam
concorrentemente e o pai espera até o filho terminar. Os processos em um sistema podem
ser independentes ou cooperantes. Os que são independentes não podem afetar ou serem
afetados pela execução de outro processo, já os cooperantes podem ser afetados pela
execução de outro processo, a cooperação entre processos tem como razões: o
compartilhamento de informações, aumento na velocidade da computação, modularidade e
conveniência.
Os processos cooperantes precisam da comunicação entre processos (IPC –
interprocess communication) que pode ser memória compartilhada e troca de mensagens. A
troca de mensagens é o mecanismo mais usado para os processos se comunicarem e
sincronizarem suas ações funciona tendo um send que é quem está mandando a
mensagem e o receive que é quem recebe o que está sendo enviado, através de um link de
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 36
comunicação entre eles.
Nesse tipo de comunicação temos duas subdivisões em relação ao seu
funcionamento: comunicação direta, onde os processos envolvidos enviam mensagens
identificando qual mandou e qual irá receber. E a comunicação indireta, que a mensagem
cai em um mailbox e se o processo que vai receber também deve estar compartilhando a
mesma mailbox. A troca de mensagens pode ser bloqueante ou não bloqueante.
Outro tipo de comunicação entre os processos é a comunicação cliente-servidor, que
subdivide em sockets, pipes, RPC (chamadas a procedimentos remoto) e a RMI
(invocação remota de método). Um socket é definido como um ponto final de
comunicação, a concatenação de um endereço IP e porta e a comunicação ocorre entre
pares de sockets. As pipes agem como canalizações permitindo a comunicação entre
processos, elas permitem a comunicação no estilo produtor-consumidor, as pipes
nomeadas são mais poderosas que os pipes comuns, p o i s não é necessária a relação paifilho entre processos comunicadores.
Já a chamada a procedimento remoto (RPC) abstrai chamadas de procedimento
entre os processos executando nos sistemas de rede e a invocação remota de método
(RMI) é um mecanismo Java similar a RPC.
4. Threads
Um pequeno programa que trabalha como um subsistema independente de um programa
maior, executando tarefas específicas. Um software dividido em várias threads pode
executar mais rápido que um programa monolítico, pois tem várias tarefas. O processo
existe para que a thread possa existir, ela funciona “em cima” dele, existem processos com
uma e com múltiplas threads. A Figura 4 mostra a comparação entre os dois modelos de
threads (uma e múltiplas).
Figura 4. Processos com uma e com múltiplas threads.
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
Os benefícios de ter as threads são responsividade e o compartilhamento de
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 37
recursos, por exemplo, em um servidor multithread (de um site de notícias, por exemplo)
cada uma de suas threads é responsável por cuidar de cada conexão com cada usuário.
Podem ser divididas em dois níveis: usuário e kernel. As threads de nível usuário tem
menores permissões de acesso e executam funções, como as API’s (Posix Pthreads,
Win32 threads e as Java threads). Já as threads em nivel kernel são mais poderosas e
liberam a CPU para a execução das de nível usuário. O sistema operacional está
organizado para ter as threads kernel.
O mapeamento das threads usuário e kernel se realiza das seguintes maneiras:
Muitos- para-um: quando várias threads são mapeadas por uma única thread kernel. Umpara-um: quando uma thread é mapeada por uma thread kernel. Muitos-para-muitos:
quando as threads usuário são mapeadas por várias threads kernel, essa é considerada a
melhor política de mapeamento. Modelo de dois níveis: quando dois tipos diferentes de
mapeamento são usados simultaneamente.
As threads trazem mais funcionalidade e agilidade na execução sendo que a
melhora já consolidada pelos processos sofre uma mutação positiva com a melhora advinda
da utilização das threads.
5. Escalonamento de CPU
Com o surgimento dos processos, threads, a ideia básica de multitarefa e a concorrência, o
sistema operacional precisou escalonar a CPU para que suportasse todos esses elementos.
Por exemplo, se temos uma CPU para duas mil threads, o sistema operacional tem que
gerenciar todas elas, os seus acessos aos recursos limitados, fazendo com que elas
executem de forma organizada, isso é o escalonamento, que se baseia em uma heurística
(algoritmo), um exemplo de escalonamento são as filas do banco, que antes eram uma fila
por cada caixa e hoje é por senha com as filas, no caso podemos apontar duas heurísticas
nesse exemplo.
No contexto de escalonamento da CPU temos o Dispatcher (despachante) ele é o
responsável por escolher quem vai receber a CPU, através da heurística que prioriza no
sistema operacional em questão.
Para que as heurísticas funcionem, elas precisam de algoritmos para se basearem
e no escalonamento de CPU, temos alguns algoritmos que são usados como o FCFS
(primeiro a chegar, primeiro a ser servido), usado no time sharing, esse algoritmo faz com
que os processos que chegam primeiro sejam executados primeiro, não importando o
tempo de cada um. Outro algoritmo que é usado é o SJF (menor job primeiro) que tem
como prioridade reduzir o tempo de espera dos processos na fila de execução. O processo
com menor tempo é executado antes. O SJF é usado quando nós sabemos o tempo dos
processos (através de uma simulação, por exemplo).
O próximo algoritmo é o de Prioridades. Cada processo tem um número de
prioridade e a CPU aloca o processo com a maior prioridade primeiro, que pode ser
preemptivo (que permite interrupções) e não preemptivo (que permite interrupções). Esse
algoritmo pode ocasionar um problema conhecido como Starvation (abandono de
processo) no caso os processos de baixa prioridade podem nunca executar. A solução
para esse problema é o aging (envelhecimento) que ao passar do tempo aumenta a
prioridade dos processos fazendo com sejam executados e não ocorra a starvation.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 38
O Round Robin (algoritmo de escalonamento circular) determina o escalonamento
através de fatias de tempo de processamento – quantum - , quando acaba esse tempo o
processo perde a CPU e essa vai para o próximo processo. A combinação dos
algoritmos Round Robin e Prioridades compõe o modo de escalonamento dos sistemas
operacionais modernos. A alocação com múltiplas filas tem por objetivos criar essas filas
com escalonamento e dar prioridades. O escalonador começa de cima para baixo.
Somente desce da fila quando está fica completa. O sistema operacional organiza as filas
conforme as suas prioridades. A desvantagem é que os processos com maior prioridades
ficam sem executar.
O último algoritmo apresentado pela Figura 5 que é o de múltiplas filas com
realimentação. Nesse algoritmo os processos transitam entre as filas (algoritmo time
sharing) os processos vai sendo medidos pela sua prioridade e são executados. Cada fila
pode ser gerenciada por um algoritmo diferente.
Figura 5. Escalonamento com múltiplas filas
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
O escalonamento de threads funciona da seguinte maneira, as threads kernel são
escalonadas pela CPU e recebem o tempo, fazendo com que as threads usuário executem
as suas instruções. No contexto do escalonamento temos o escalonamento com vários
processadores homogêneos que dão mais poder de processamento na fila, a CPU é
entregue mais rápido e o escalonamento vai mais ligeiro. E com processadores multicore
quando há um processador que suporta vários tipos de execução.
6. Sincronização de Processos
O compartilhamento de recursos entre processos pode gerar situações indesejáveis, os
mecanismos de sincronização garantem a comunicação entre processos concorrentes.
Com o acesso dos dados compartilhados surgiu o problema da região crítica e a
sincronização apresenta soluções para esse problema.
A sincronização tem como um de seus objetivos manter a consistência de dados,
requerendo a utilização de mecanismos para garantir a execução ordenada de processos
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 39
cooperantes. Algumas soluções para o problema da região crítica são a exclusão mútua,
progresso e a espera limitada.
A exclusão mútua acontece quando um processo está executando sua região critica e
outro processo pode estar querendo executar a sua região crítica. O progresso é quando
nenhum processo está executando uma região crítica e existem processos que desejam
entrar nas regiões críticas deles, então a escolha do próximo processo que irá entrar na
região crítica ao pode ser adiada indefinidamente.
A espera limitada acontece quando existe um limite para o número de vezes que os
outros processos são selecionados para entrar nas regiões criticas deles, depois que um
processo fez uma requisição para entrar em sua região crítica e antes que essa requisição
seja atendida. Muitos sistemas fornecem suporte de hardware para código de seção crítica
como os sistemas monoprocessados, que podem desabilitar interrupção, o código em
execução pode executar sem preempção, geralmente muito ineficiente em sistemas
multiprocessados, os sistemas operacionais que usam isso não escalam.
As arquiteturas modernas fornecem instruções atômicas especiais de hardware como
testar uma posição de memória e setar um valor ou trocar conteúdos de duas posições na
memória. Dentre as soluções também podemos contar com o uso de Lock (bloqueios),
Instruções test and set, Swap, Semáforo e Monitores.
O Semáforo é a solução mais geral e simples de ser implementada, variável inteira
que só pode ser manipulada por duas instruções wait e signal, na exclusão mútua essas
instruções funcionam como protocolos de entrada e saída, valor maior a zero, recurso
liberado, valor igual à zero, processo impedido de acesso. A solução trazida pelos
semáforos é aplicada ao problema de sincronização condicional, em geral se existe um
processo que deve ser notificado sobre a ocorrência, pode-se utilizar um semáforo
associado ao evento esperado para sincronizar ambos os recursos ao mesmo tempo.
Existe o Semáforo Circular que permite somente valores inteiros e o Semáforo
Binário com valores em zero e um. O problema do Semáforo é que é difícil para programar,
identificando as regiões críticas colocando um wait e signal, caso aconteça o
esquecimento de uma só pode gerar vários problemas.
Os monitores, mostrado pela Figura 6, são abstrações de alto nível que fornecem
um mecanismo conveniente de sincronização de processos, somente um processo pode
estar ativo dentro do monitor, é como se fosse uma classe, os processos “chamam” os
procedimentos e após liberar o outro processo entra. Cada linguagem tem sua sintaxe para
ter os monitores.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 40
Figura 6. Funcionamento de um Monitor
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
7. Deadlocks
Um estado de deadlock ocorre quando dois ou mais processos estão esperando
indefinidamente por um evento que só pode ser causado por um dos processos em espera.
Em princípio existem três métodos para tratar deadlocks:



Usar algum protocolo para garantir que o sistema nunca entre em estado de
deadlock;
Permitir que o sistema entre em estado de deadlock e depois se recupere;
Ignorar o problema e fingir que os deadlocks nunca ocorrem no sistema.
A terceira solução é usada pela maioria dos sistemas operacionais, incluindo o UNIX
e a JVM. Uma situação de deadlock poderá ocorrer se e somente quatro condições
necessárias forem válidas ao mesmo tempo no sistema: exclusão mútua, posse e espera,
não-preempção e espera circular. Para prevenir deadlocks, é preciso garantir que ao menos
uma das condições necessárias nunca seja válida.
Outro método para evitar deadlocks, menos estrito do que os algoritmos de
prevenção é ter informações, primeiramente, sobre como cada processo estará utilizando o
recurso. Usando essas informações, é possível definir um algoritmo que poderá impedir os
deadlocks. Se um sistema não utilizar protocolo para garantir que os deadlocks nunca
ocorrerão, um esquema de detecção e recuperação deverá ser empregado.
Um algoritmo de detecção de deadlocks deverá ser acionado para verificar se este
ocorreu ou não, caso seja verificado e tenha ocorrido, o sistema deverá se recuperar
terminado alguns dos processos em deadlock ou efetuando a preempção de recursos a
partir de alguns dos processos em deadlock.
Em um sistema que seleciona as vitimas para o rollback (exclusão, preempção)
principalmente com base nos fatores de custo, poderá ocorrer uma paralisação. Como
resultado, o processo selecionado nunca concluirá a tarefa que lhe foi designada.
Segundo Silberschatz (2004, p.174) os pesquisadores vêm discutindo o fato de que
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 41
nenhuma dessas abordagens por si só é apropriada para todo o espectro de problemas de
alocação de recursos nos sistemas operacionais. As abordagens básicas podem ser
combinadas, permitindo a seleção separada de uma solução ótima para cada classe de
recursos em um sistema.
8. Gerência de Memória
O gerenciador de memória controla quais partes da memória estão sendo utilizadas e quais
não estão. Além disso, ele é responsável por alocar espaço em memória aos processos que
serão executados e liberar as posições de memória ocupadas quando os processos são
finalizados. Outra funcionalidade do gerenciador de memória é controlar o swapping de
informação, constante na execução das aplicações. Para iniciar a discussão sobre o tema da
aula vamos entender, primeiramente, a função da MMU.
A MMU é um módulo de hardware que faz o mapeamento entre os endereços lógicos
(end. da memória virtual) e os endereços físicos da memória (RAM), ou seja, é um
dispositivo que transforma endereços virtuais em endereços físicos. Para isso, a MMU
normalmente traduz número de páginas virtuais para número de páginas físicas utilizando
uma cache chamada Translation Lookside Buffer (TLB). Na figura abaixo temos ilustrado o
mecanismo de tradução dos endereços.
Podemos classificar os gerenciadores de memória em dois tipos: os que permitem as
trocas de processos entre a memória principal e o disco (troca de processos e paginação,
mais complexos) e os que não permitem (muito mais simplificados e limitados). A
necessidade da troca de processos e paginação acontece devido a quantidade insuficiente de
memória principal para armazenar vários programas ao mesmo tempo. Hoje em dia, as
máquinas adotam um modelo denominado multiprogramação e, portanto, os algoritmos
necessitam gerenciar várias aplicações que concorrem ao uso das unidades de
processamento e armazenamento de dados.
9. Memória Virtual
A memória virtual é uma técnica que permite o mapeamento de um espaço de
endereçamento lógico grande em uma memória física menor. A memória virtual permite
que processos extremamente grandes sejam executados, e que o grau de multiprogramação
seja elevado, melhorando o desempenho da CPU. Além disso, ela libera os programadores
de aplicações de preocupação de pensar na disponibilidade da memória, como mostra a
figura abaixo, onde a memória virtual mapeia os endereços para dar sequência à execução
das instruções selecionadas.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 42
Figura 7. Funcionamento da paginação
Fonte: http://professor.unisinos.br/barbosa/SO/so.htm
Uma das estratégias de implementação dessa técnica é a paginação, como mostra a
Figura 7, que nunca leva uma sequência de páginas para a memória até que esta seja
referenciada. A primeira referência causa uma falta de páginas para o monitor residente do
sistema operacional que consulta uma tabela interna de páginas para determinar onde a
página está localizada no armazenamento auxiliar. A tabela de páginas é atualizada para
refletir essa mudança, e a instrução que causou a falta de página é reiniciada. Essa
abordagem permite que um processo execute mesmo que sua imagem de memória completa
não esteja na memória principal de uma vez. Desde que a taxa de falta de página seja
razoavelmente baixa, o desempenho será aceitável.
A paginação pode ser usada para reduzir o número de quadros alocados a um
processo. Esse arranjo pode aumentar o grau de multiprogramação (permitindo a
execução de vários processos disponíveis para execução ao mesmo tempo) e, ao menos
em teoria, aumenta a utilização da CPU do sistema. Permitindo assim que os processos
sejam executados mesmo que suas exigências de memória superem a memória física total
disponível, pois estes executam na memória virtual.
Se os requisitos de memória total excederem a memória física, pode ser necessário
substituir as páginas da memória para liberar quadros para novas páginas. Vários
algoritmos de são utilizados com este intuito. A substituição de página FIFO é fácil de
programar, já a substituição de página ótima requer conhecimento futuro. A substituição
LRU é uma aproximação da substituição ótima, mas mesmo ela pode ser difícil de
implementar. A maioria dos algoritmos de substituição de página, tais como o de
segunda chance, são aproximações da substituição LRU.
Além de um algoritmo de substituição de página, é necessária uma política de
alocação de quadros. A alocação pode ser fixa, sugerindo a substituição de página local,
ou dinâmica, sugerindo a substituição global. O modelo de conjunto de trabalho assume
que os processos executam em localidades. O conjunto de trabalho é o conjunto de
páginas na localidade atual. Da mesma forma, cada processo deve receber um número de
quadros suficientes para seu conjunto de trabalho atual.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 43
Se um processo não tiver memória suficiente para seu conjunto de trabalho, ele
entrará em thrashing. Fornecer quadros suficientes para cada processo a fim de evitar o
thrashing pode exigir swapping e o escalonamento de processos.
Além de exigir a resolução dos principais problemas de substituição de página e
alocação de quadros, o projeto adequado de um sistema de paginação requer que
consideremos o tamanho de página, I/O, travamento, pré-paginação, estrutura dos
programas e outros tópicos. A memória virtual pode ser considerada um nível de uma
hierarquia de níveis de armazenamento em um sistema de computação. Cada nível tem
seu próprio tempo de acesso, tamanho e parâmetros de custo.
10. Sistema de Arquivos
Um arquivo é um tipo abstrato de dados definido e implementado pelo sistema operacional.
É uma sequência de registros lógicos. Um registro lógico pode ser um byte, uma linha (de
tamanho fixo ou variável) ou um item de dados mais complexo. O sistema operacional pode
suportar especificamente vários tipos de registro ou pode deixar o suporte ao programa
aplicativo.
A principal tarefa do sistema operacional é mapear o conceito de arquivo lógico em
dispositivos de armazenamento físico tais como fita ou disco magnético. Como o tamanho
do registro físico do dispositivo talvez não seja igual ao tamanho do registro lógico, pode
ser necessário encaixar registros lógicos em registros físicos. Mais uma vez, essa tarefa
pode ser suportada pelo sistema operacional ou deixada para o programa aplicativo.
Os sistemas de arquivos baseados em fita são limitados; a maioria dos sistemas de
arquivos são baseados em disco. As fitas são comumente usadas para transporte de dados
entre máquinas, ou para armazenamento de backup ou arquivamento.
Cada dispositivo em um sistema de arquivos mantêm um índice de volume ou
diretório de dispositivo listando a posição dos arquivos no dispositivo. Além disso, é útil
criar diretórios para permitir a organização dos arquivos. Um diretório de nível único em
um sistema multiusuário causa problemas de nomeação, já que cada arquivo deve ter um
nome exclusivo. Um diretório de dois níveis resolve esse problema criando um diretório
separado para cada usuário. Cada usuário tem seu próprio diretório, que contém seus
próprios arquivos.
O diretório lista os arquivos por nome, e inclui informações como a posição do
arquivo no disco, seu tamanho, tipo, proprietário, hora da criação, hora da última utilização
etc. A generalização natural de um diretório de dois níveis é um diretório estruturado em
árvore. Um diretório em árvore permite que o usuário crie subdiretórios para organizar seus
arquivos. Estruturas de diretórios de grafos acíclicos permitem o compartilhamento de
arquivos e diretórios, mas complicam a pesquisa e exclusão.
Uma estrutura de grafo genérico permite flexibilidade total no compartilhamento de
arquivos e diretórios, mas às vezes requer o uso da coleta de lixo para recuperar espaço em
disco não utilizado. Como os arquivos são o principal mecanismo de armazenamento de
informações na maioria dos sistemas de computação, a proteção de arquivo é necessária. O
acesso aos arquivos pode ser controlado de forma separada para cada tipo de acesso: ler,
gravar, executar, anexar, listar diretório e assim por diante.
A proteção de arquivo pode ser fornecida por senhas, listas de acesso, ou por técnicas
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 44
especiais ad hoc. O sistema de arquivos reside permanentemente no armazenamento
secundário, que tem como exigência principal o fato de poder armazenar grandes
quantidades de dados de forma permanente. O meio de armazenamento secundário mais
comum é o disco.
Os sistemas de arquivos são muitas vezes implementados em uma estrutura em
camadas ou modular. Os níveis inferiores tratam das propriedades físicas dos dispositivos
de armazenamento. Os níveis superiores lidam com nomes de arquivo simbólicos e as
propriedades lógicas dos arquivos. Os níveis intermediários mapeiam os conceitos de
arquivo lógico em propriedades de dispositivos físicos.
Os vários arquivos podem ser alocados no disco de três formas: através de alocação
contígua, encadeada ou indexada. A alocação contígua pode sofrer de fragmentação
externa. O acesso direto é muito ineficiente com a alocação encadeada. A alocação
indexada pode exigir custo substancial para seu bloco de índice. Existem muitas formas nas
quais esses algoritmos podem ser otimizados. O espaço contíguo pode ser ampliado por
meio de extensões para aumentar a flexibilidade e diminuir a fragmentação externa. A
alocação indexada pode ser feita em clusters de múltiplos blocos para aumentar o
throughput e reduzir o número de entradas de índice necessárias. A indexação em clusters
grandes é semelhante à alocação contígua com extensões.
Os métodos de alocação de espaço livre também influenciam a eficiência de uso do
espaço em disco, o desempenho do sistema de arquivos, e a confiabilidade do
armazenamento secundário. Os métodos usados incluem vetores de bits e listas encadeadas.
As otimizações incluem agrupamento, contadores e a FAT, que coloca a lista encadeada em
uma área contígua.
As rotinas de gerência de diretórios devem considerar os aspectos de eficiência,
desempenho e confiabilidade. Uma tabela de dispersão é o método mais frequentemente
usado; é rápido e eficiente. Infelizmente, danos à tabela ou uma falha no sistema podem
fazer com que as informações do diretório não correspondam ao conteúdo do disco. Um
verificador de consistência - um programa de sistema como o chkdsk no MS-DOS - pode
ser usado para reparar o dano.
7. Conclusão
Os sistemas operacionais são softwares extremante complexos, que tem como missão
manter em equilíbrio a execução de programas e o hardware se comunicando com o
usuário, ou seja, interagindo com todos os componentes envolvidos no sistema de
computação. Entende-los não é tarefa fácil devida tamanha complexidade e estrutura da
qual gerenciam de forma a ter um ótimo custo-benefício para ambas às partes hardware e
usuário.
A facilidade de interação entre o usuário e máquina é tamanha que não nos damos
conta da complexidade desse sistema, é ele quem administra e executa todos os pedidos
do usuário. O sistema computacional tem a forma atual devido aos sistemas operacionais
que são os responsáveis por fazer essa conexão entre quem utiliza o hardware e o próprio
usuário.
Todos os usuários, na atualidade usam e não se imaginam em um computador
que não tenha um sistema operacional sendo executado. O sistema operacional se tornou
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 45
tão importante que para muitos somente ele transmite a ideia de ser o “próprio
computador”. Esse software é de extrema importância, já que atua como mediador entre
o hardware e os softwares que estão instalados no computador. Os sistemas operacionais
estão sofrendo grandes atualizações e tem versões para vários estilos de usuários com a
intenção de tentar se adaptar, fazendo com que o seu usuário ao interagir de forma a
tornar-se imperceptível.
Referências
Silberschatz, A.; Galvin, P.B.; Gagne, G. Fundamentos de Sistemas Operacionais. 6ª ed.
Rio de Janeiro: LTC, 2004.
Revista iTEC – Vol. 4, Nº 4, Jul. 2012
Página 46
Download

Instruções aos Autores de Contribuições para o SIBGRAPI