Logo Passei Direto
Buscar

Sistemas Operacionais

Ferramentas de estudo

Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

left-side-bubbles-backgroundright-side-bubbles-background

Crie sua conta grátis para liberar esse material. 🤩

Já tem uma conta?

Ao continuar, você aceita os Termos de Uso e Política de Privacidade

Prévia do material em texto

Sistemas Operacionais 
Marcio Quirino - 1 
 
SUMÁRIO 
Caminho do Brilho: Saiba Quais Conteúdos Você Irá Aprender Conosco........................................... 8 
Onboarding ......................................................................................................................................... 8 
Conceitos Básicos de SO ...................................................................................................................... 9 
Descrição ............................................................................................................................................ 9 
Propósito ............................................................................................................................................. 9 
Introdução ........................................................................................................................................... 9 
Conceitos ............................................................................................................................................ 9 
Histórico dos sistemas computacionais ........................................................................................... 11 
Primeira geração ...................................................................................................................................... 11 
Segunda geração ..................................................................................................................................... 12 
Terceira geração ...................................................................................................................................... 13 
Quarta geração ........................................................................................................................................ 13 
MS Windows e UNIX ........................................................................................................................ 14 
Windows ................................................................................................................................................... 14 
MS-DOS ............................................................................................................................................... 14 
MS Windows 1.0 .................................................................................................................................. 14 
Windows NT ......................................................................................................................................... 14 
Windows 2000 ...................................................................................................................................... 14 
Windows XP ......................................................................................................................................... 14 
Outras versões ..................................................................................................................................... 14 
Unix .......................................................................................................................................................... 14 
1965 ..................................................................................................................................................... 14 
1969 ..................................................................................................................................................... 15 
1973 ..................................................................................................................................................... 15 
1991 ..................................................................................................................................................... 15 
Tipos de Sistemas Operacionais ..................................................................................................... 15 
Sistemas Monoprogramáveis ................................................................................................................... 15 
Sistemas Multiprogramáveis ou Multitarefa .............................................................................................. 16 
Sistemas com múltiplos processadores .......................................................................................... 18 
Sistemas fortemente acoplados ............................................................................................................... 18 
SMP - Symmetric Multiprocessors ....................................................................................................... 18 
NUMA - Non-Uniform Memory Access ................................................................................................. 18 
Sistemas fracamente acoplados .............................................................................................................. 19 
Outras classificações dos sistemas operacionais ........................................................................... 19 
Sistemas em lote ...................................................................................................................................... 19 
Sistemas de processamento de transações ............................................................................................. 19 
Sistemas de tempo compartilhado ........................................................................................................... 19 
Sistema de tempo real crítico ................................................................................................................... 20 
Sistema de tempo real não crítico ............................................................................................................ 20 
Sistemas Operacionais 
Marcio Quirino - 2 
 
Software proprietário ................................................................................................................................ 20 
Software livre (free software).................................................................................................................... 20 
Software de código aberto (open source) ................................................................................................ 20 
Estrutura do SO: Kernel, System Calls, Modos de Acesso............................................................. 21 
System Calls ............................................................................................................................................ 22 
Modos de acesso ..................................................................................................................................... 26 
Modo kernel ou supervisor ................................................................................................................... 26 
Modo de acesso usuário ...................................................................................................................... 26 
Arquiteturas de kernel .............................................................................................................................. 26 
Arquitetura monolítica (mono-kernel) ................................................................................................... 26 
Arquitetura de camadas ....................................................................................................................... 27 
Máquina virtual ou virtual machine (VM) .............................................................................................. 28 
Arquitetura microkernel ........................................................................................................................ 29 
Exonúcleo ............................................................................................................................................. 29 
Conceitos ..........................................................................................................................................30 
Estrutura de diretórios no Linux ....................................................................................................... 31 
Comandos do Linux ......................................................................................................................... 32 
Comandos básicos para uso via terminal ................................................................................................. 33 
Considerações finais ........................................................................................................................ 35 
Referências....................................................................................................................................... 35 
Explore+ ........................................................................................................................................... 35 
Processos e Gerencia de Processador ............................................................................................... 36 
Definição ........................................................................................................................................... 36 
Propósito ........................................................................................................................................... 36 
Preparação ....................................................................................................................................... 36 
Introdução ......................................................................................................................................... 36 
Conceitos .......................................................................................................................................... 36 
Modelo de processo ................................................................................................................................. 37 
Criação e encerramento de processos ............................................................................................ 38 
Hierarquia de processos .......................................................................................................................... 40 
Estados de processos ...................................................................................................................... 42 
Mudança de contexto ............................................................................................................................... 43 
Contexto de hardware .......................................................................................................................... 43 
Contexto de software............................................................................................................................ 44 
Espaço de endereçamento................................................................................................................... 44 
Processos no Linux .......................................................................................................................... 44 
Comandos do shell ........................................................................................................................... 44 
Comandos para controle de processos ........................................................................................... 46 
ps ............................................................................................................................................................. 46 
Sistemas Operacionais 
Marcio Quirino - 3 
 
top ............................................................................................................................................................ 46 
<Ctrl> + <C> ............................................................................................................................................. 46 
<Ctrl> + <Z> ............................................................................................................................................. 47 
jobs ........................................................................................................................................................... 47 
bg ............................................................................................................................................................. 47 
fg .............................................................................................................................................................. 47 
kill ............................................................................................................................................................. 47 
killall ......................................................................................................................................................... 47 
killall5 ....................................................................................................................................................... 47 
nohup ....................................................................................................................................................... 47 
pstree ....................................................................................................................................................... 47 
Exemplos: ............................................................................................................................................. 48 
Subprocesso ..................................................................................................................................... 49 
Threads ............................................................................................................................................. 50 
Tipos de processos .................................................................................................................................. 53 
Processos e Threads No Linux ........................................................................................................ 53 
Processos de aplicações concorrentes ........................................................................................... 54 
Condição de corrida ......................................................................................................................... 54 
Região crítica ........................................................................................................................................... 55 
Semáforos ................................................................................................................................................ 55 
Utilização de semáforo na solução de condição de corrida ..................................................................... 57 
ANEXO I ............................................................................................................................................... 57 
ANEXO II .............................................................................................................................................. 58 
Monitores .......................................................................................................................................... 60 
Sincronização no Linux .................................................................................................................... 61 
Tratamento de sinais em Linux ................................................................................................................ 63 
Exemplo para tratamento de sinais ...................................................................................................... 64 
Escalonamento ................................................................................................................................. 64 
Escalonamento First In First Out (FIFO) ..................................................................................................65 
Escalonamento Shortest Job First (SJF) .................................................................................................. 65 
Escalonamento Shortest Remaining Time Next (SRTN) .......................................................................... 66 
Escalonamento Cooperativo .................................................................................................................... 66 
Escalonamento Circular (Round Robin) ................................................................................................... 66 
Escalonamento por Prioridade ................................................................................................................. 67 
Escalonamento por Múltiplas Filas ........................................................................................................... 67 
Escalonamento em Sistemas de Tempo Real.......................................................................................... 68 
Escalonamento de Threads...................................................................................................................... 68 
Escalonamento no Linux .................................................................................................................. 69 
Considerações finais ........................................................................................................................ 70 
Referências....................................................................................................................................... 70 
Sistemas Operacionais 
Marcio Quirino - 4 
 
Explore+ ........................................................................................................................................... 71 
Memória ............................................................................................................................................... 72 
Descrição .......................................................................................................................................... 72 
Propósito ........................................................................................................................................... 72 
Introdução ......................................................................................................................................... 72 
Gerência de memória ....................................................................................................................... 72 
Como os processos enxergam a memória ............................................................................................... 74 
Proteção de memória ............................................................................................................................... 75 
Relocação ................................................................................................................................................ 77 
Políticas de alocação ....................................................................................................................... 79 
Gerenciamento de memória sem permuta ...................................................................................... 79 
Alocação contígua .................................................................................................................................... 79 
Overlay ..................................................................................................................................................... 79 
Alocação particionada fixa ....................................................................................................................... 81 
Alocação com partições variáveis ............................................................................................................ 82 
Política Best-Fit ........................................................................................................................................ 84 
Política First-Fit ........................................................................................................................................ 84 
Política Worst-Fit ...................................................................................................................................... 85 
Fragmentação externa e interna ...................................................................................................... 85 
Gerenciamento de memória com permuta ...................................................................................... 86 
Swap de memória .................................................................................................................................... 86 
Gerenciamento de espaço livre ....................................................................................................... 87 
Gerenciamento de memória com mapas de bits ...................................................................................... 87 
Gerenciamento de memória com listas encadeadas ................................................................................ 88 
Memória virtual ................................................................................................................................. 89 
Paginação ......................................................................................................................................... 90 
Controle de espaço livre ........................................................................................................................... 90 
Proteção de memória ............................................................................................................................... 91 
Paginação sob demanda .......................................................................................................................... 92 
Políticas de paginação ............................................................................................................................. 92 
Algoritmo de segunda chance .................................................................................................................. 93 
Segmentação ........................................................................................................................................... 95 
Gerenciamento de memória no Linux .............................................................................................. 96 
Gerenciamento da memória física no Linux .................................................................................... 96 
Memória virtual no Linux .................................................................................................................. 97 
Regiões de memória virtual ...................................................................................................................... 97 
Tempo de vida de um espaço de endereçamento virtual ......................................................................... 97 
Permuta e paginação ............................................................................................................................... 98 
Execução e carga de programas de usuário ................................................................................... 98 
Sistemas Operacionais 
Marcio Quirino - 5 
 
Mapeamento de programas para a memória ........................................................................................... 98 
Vinculação estática e dinâmica ................................................................................................................ 99 
Utilitários e comandos para gerenciar a memória do sistema Linux ............................................ 100 
Obtendo informações pela linha de comando ........................................................................................ 100 
Utilitários para acesso à informação ......................................................................................................101 
Htop .................................................................................................................................................... 101 
Ksysguard .............................................................................................................................................. 103 
Monitor do Sistema ................................................................................................................................ 104 
Considerações finais ...................................................................................................................... 105 
Referências..................................................................................................................................... 105 
EXPLORE+ ..................................................................................................................................... 105 
Sistema de Arquivos .......................................................................................................................... 106 
Descrição ........................................................................................................................................ 106 
Propósito ......................................................................................................................................... 106 
Preparação ..................................................................................................................................... 106 
Introdução ....................................................................................................................................... 106 
Conceitos ........................................................................................................................................ 106 
Arquivos .......................................................................................................................................... 107 
Estrutura de Arquivos ............................................................................................................................. 108 
Métodos de Acesso ................................................................................................................................ 109 
Tipos de Arquivos ................................................................................................................................... 109 
Diretórios ........................................................................................................................................ 110 
Implementação do sistema de arquivos ........................................................................................ 111 
Alocação Contígua ................................................................................................................................. 112 
Alocação por Lista Encadeada ............................................................................................................... 113 
Alocação por Lista Encadeada Utilizando Índice.................................................................................... 114 
I-nodes (Alocação Indexada).................................................................................................................. 114 
IMPLEMENTAÇÃO DE CACHE .................................................................................................... 115 
O sistema de arquivos do Linux ..................................................................................................... 116 
ext2 ................................................................................................................................................. 118 
Journaling ....................................................................................................................................... 120 
Disco Rígido ................................................................................................................................... 121 
Partições ......................................................................................................................................... 121 
Gerenciamento de partições em Linux ................................................................................................... 122 
Formatação ............................................................................................................................................ 129 
Formatação de partições em Linux ........................................................................................................ 129 
Montagem do sistema de arquivos ................................................................................................ 130 
Montagem de partições em Linux .......................................................................................................... 131 
Outros comandos para gerenciamento de partições..................................................................... 135 
Sistemas Operacionais 
Marcio Quirino - 6 
 
Conceitos ........................................................................................................................................ 136 
Comandos para manipulação de diretórios ................................................................................... 137 
Comandos para manipulação de arquivos .................................................................................... 139 
Links simbólicos e hardlinks ........................................................................................................... 142 
Editor de arquivos x processador de textos................................................................................... 143 
vim .......................................................................................................................................................... 144 
Principais comandos do vim ............................................................................................................... 144 
Montagem de partições em Linux .......................................................................................................... 146 
nano ....................................................................................................................................................... 150 
gedit ....................................................................................................................................................... 150 
Considerações finais ...................................................................................................................... 152 
Referências..................................................................................................................................... 152 
Explore+ ......................................................................................................................................... 153 
Automatizando Tarefas no Linux ....................................................................................................... 154 
Descrição ........................................................................................................................................ 154 
Propósito ......................................................................................................................................... 154 
Preparação ..................................................................................................................................... 154 
Introdução ....................................................................................................................................... 154 
Conceitos ........................................................................................................................................ 154 
Ferramenta multiusuário ................................................................................................................155 
Como configurar o cron de usuário ................................................................................................ 155 
Regras e formatos do crontab........................................................................................................ 156 
Exemplo de uma tarefa automática de backup ............................................................................. 158 
A configuração de cron para o sistema ......................................................................................... 158 
Conceitos ........................................................................................................................................ 159 
O interpretador de shell .................................................................................................................. 159 
A palavra mágica que identifica um script ..................................................................................... 159 
Um script muito simples ................................................................................................................. 159 
Linhas em branco e comentários ................................................................................................... 160 
Incluindo textos na resposta do script............................................................................................ 161 
Inserindo caracteres especiais no comando ‘echo’ ....................................................................... 162 
Criando pausas na execução de um script .................................................................................... 162 
Apagando todo o conteúdo do terminal ......................................................................................... 163 
Terminando um script com valor de retorno .................................................................................. 163 
Conceitos ........................................................................................................................................ 164 
Atribuição de valores a uma variável ............................................................................................. 164 
Referenciando variáveis ................................................................................................................. 164 
Atribuição da saída de um comando a uma variável..................................................................... 165 
Sistemas Operacionais 
Marcio Quirino - 7 
 
Passando parâmetros para o script ............................................................................................... 165 
O operador lógico if ........................................................................................................................ 166 
Comparadores numéricos .............................................................................................................. 166 
Comparadores de cadeias de caracteres (strings)........................................................................ 168 
Executando o script sem parâmetros ............................................................................................ 169 
Realizando operações aritméticas em script ................................................................................. 170 
Incrementando variáveis ................................................................................................................ 171 
Operações com ponto flutuante ..................................................................................................... 171 
Conceitos ........................................................................................................................................ 172 
A estrutura de repetição while........................................................................................................ 173 
Interferindo na execução de um loop............................................................................................. 174 
A estrutura de repetição for ............................................................................................................ 175 
Obtendo uma variável a partir de um arquivo texto....................................................................... 179 
Considerações ao executar um script a partir do cron .................................................................. 179 
Considerações finais ...................................................................................................................... 181 
Referências..................................................................................................................................... 181 
Explore+ ......................................................................................................................................... 181 
Sistemas Operacionais 
Marcio Quirino - 8 
 
Sistemas Operacionais 
Caminho do Brilho: Saiba Quais Conteúdos Você Irá 
Aprender Conosco 
Onboarding 
É com grande entusiasmo que apresentamos a disciplina de Sistemas Operacionais, um dos pilares 
essenciais para a sua formação e desenvolvimento profissional na área de Computação. Ao longo deste 
percurso, você irá perceber como os conhecimentos adquiridos aqui são fundamentais para construir uma 
carreira sólida e buscar oportunidades no mundo de trabalho. 
A jornada que começamos a trilhar aqui abordará uma série de tópicos cruciais para sua formação 
como profissional. Desde a evolução histórica dos sistemas operacionais até a aplicação prática de 
comandos no Linux, cada passo desse caminho é uma conquista em direção ao sucesso profissional. 
Ao compreender a evolução dos sistemas operacionais, você entenderá como chegamos aos 
sistemas que utilizamos hoje, e isso lhe dará uma base sólida para acompanhar as constantes mudanças 
nessa área dinâmica. Além disso, ao identificar os tipos de sistemas operacionais e entender a estrutura do 
Sistema Operacional, incluindo o Kernel, system calls e modos de acesso, você estará equipado para lidar 
com sistemas diversos e complexos. 
Aqui, você também aprenderá sobre processos e programação concorrente, habilidades essenciais 
em um ambiente de TI que exige eficiência e multitarefa. Compreenderá como os processos se comunicam 
e como o escalonamento de tarefas é crucial para um sistema operacional eficaz. 
A gestão de memória é outra área crítica em nossa jornada. Você descobrirá como a memória é 
alocada e gerenciada, e como o Linux lida com esse aspecto fundamental. Além disso, entenderá como os 
sistemas de arquivos funcionam e como usar ferramentas de gerenciamento no Linux para manipular 
arquivos com eficiência. 
Para a automação de tarefas, aprenderemos a criar scripts e agendamentos, tornando seu trabalho 
mais eficiente e produtivo. O uso de variáveis de ambiente e estruturas de decisão em scripts permitirá que 
você realize tarefas complexas de forma automatizada. 
Em resumo, esta disciplina não apenas ampliará seus conhecimentos técnicos, mas também abrirá 
portas para o mercado de trabalho em constante evolução. Valorize cada conquista e transformação do 
saber, pois elas o aproximam do sucesso profissional que tanto almeja. 
Lembre-se de que você está na universidade para crescer e se desenvolver. Cada conhecimento 
adquirido aqui é uma ferramenta valiosa em sua jornada como profissional. Mantenha-se curioso, 
comprometido e, acima de tudo, feliz com seu aprendizado, pois essa paixão pelo conhecimento é o que 
diferencia os melhores profissionais. 
 
Sistemas Operacionais 
Marcio Quirino - 9 
 
Conceitos Básicos de SO 
Descrição 
A conceituação dos elementos de um sistema operacional, desde a sua evolução histórica, passando 
pela estrutura básica, até a exemplificação da instalação e utilização do sistema operacional Linux, sob o 
ponto de vista do usuário. 
Propósito 
Compreender os conceitos básicos que formam os sistemas operacionaisé importante para a 
solidificação do seu leque de conhecimentos fundamentais em sistemas de computação, possibilitando 
expandir a percepção de mais detalhes relacionados aos assuntos que envolvem computadores. 
Introdução 
Qualquer sistema computacional é composto pelo conjunto de usuários, hardware e software. Dentre 
os softwares que são utilizados, podemos separá-los nos aplicativos que são disponibilizados pelos usuários 
e os sistemas operacionais. 
Os sistemas operacionais (SO) oferecem uma interface entre os aplicativos e o hardware, tornando 
a vida dos usuários e dos desenvolvedores mais simples. Além disso, o sistema operacional permite um uso 
mais eficiente e eficaz do hardware. 
Para conseguirmos reconhecer o papel do sistema operacional, iremos descobrir um pouco de como 
eles surgiram e evoluíram junto aos próprios sistemas computacionais. 
Iremos aprender os tipos de sistemas operacionais, bem como compreender a estrutura básica do 
sistema operacional, composto, dentre outros elementos, do kernel, chamadas de sistemas e modos de 
acesso ao núcleo. 
Por fim, vamos verificar como é a utilização básica de um sistema operacional, aplicando conceitos 
ao uso do SO Linux. 
1. Evolução histórica dos SO 
Descrever a evolução histórica dos Sistemas Operacionais. 
Conceitos 
Estamos prestes a realizar o nosso estudo em sistemas operacionais. Esse assunto é importante 
para todos os profissionais que buscam exercer plenamente suas atividades nas diversas áreas da 
computação, como administradores de sistemas, programadores de aplicações concorrentes, gerentes de 
segurança e administradores de rede (devido aos sistemas operacionais nas redes de comunicação de 
dados). 
Vamos começar verificando quais são os componentes básicos de um sistema computacional (ou 
sistema de computação ou S.C.): 
1. Hardware 
✓ Fornece recursos básicos de computação CPU, memória, dispositivos de E/S. 
 
Sistemas Operacionais 
Marcio Quirino - 10 
 
2. Aplicativos 
✓ Definem as maneiras como os recursos são usados, para resolver os problemas de 
computação dos usuários, como compiladores, banco de dados, jogos de videogames, 
programas comerciais e outros. 
3. Usuários 
✓ São as pessoas, máquinas ou outros computadores. 
4. Sistema Operacional 
✓ Controla e coordena o uso do hardware entre os vários programas de aplicação, para os 
diversos usuários. 
O sistema computacional é um sistema complexo demais. Não apenas para ser entendido nos 
mínimos detalhes, como também para realizar a gerência de todos os seus componentes e usá-los de modo 
otimizado. Por esse motivo é que os computadores possuem um software denominado sistema operacional. 
Uma das definições possíveis para um sistema operacional (abreviado muitas vezes por SO, ou S.O.) 
é ser constituído por um conjunto de rotinas de computação elaborado para propósitos específicos, de forma 
semelhante com o que ocorre com um aplicativo de computador que utilizamos no dia a dia, por exemplo, 
uma planilha eletrônica. Porém, há uma particularidade: 
O sistema operacional se diferencia de um aplicativo de usuário ao atuar como um intermediário entre o usuário 
e o hardware de um computador, tornando a utilização deste mais simples, rápida e segura. 
 
Figura 1 – Sistemas Operacionais. Fonte: Rose Carson/Shutterstock. 
Você já deve ter utilizado sistemas operacionais tais como o Windows, o Linux, o Mac OS X ou o 
Android, mas as aparências podem enganar: 
Atenção 
O programa que serve para a interação dos usuários na realidade não faz parte do sistema operacional em si, 
embora usem o SO para realizar seu trabalho. Na realidade, o que usuário utiliza diretamente é uma interface de 
acesso ao sistema operacional. Essa interface pode ser baseada em texto (shell, ou interpretador de comandos), ou 
baseado em interface gráfica com ícones (GUI - Graphical User Interface). 
Em um computador, os programas podem ser executados em modo usuário ou kernel. No modo 
usuário, os softwares têm acesso limitado ao hardware e normalmente estão os programas e aplicativos 
utilizados diretamente pelos usuários. 
O SO é o único programa executado em modo núcleo, ou Kernel. Significa que o SO possui o acesso completo 
ao hardware e consegue executar qualquer instrução possível. 
Além disso, o sistema operacional é um programa de controle que coordena a execução dos 
programas do usuário e as operações dos dispositivos de E/S (entrada e saída, ou periféricos); e também é 
um gerenciador de recursos de hardware, que gerencia e aloca as partes de todo um sistema complexo. 
Sistemas Operacionais 
Marcio Quirino - 11 
 
Você sabia 
Nos primeiros computadores, a programação era toda feita através de painéis físicos, exigindo do programador 
um grande conhecimento do hardware, mas o hardware em si possuía pouca utilidade para o usuário devido à sua 
complexidade. 
O surgimento do sistema operacional permitiu que o hardware pudesse ser utilizado de forma mais eficiente, 
levando em consideração que o SO consegue disponibilizar de forma mais eficiente os serviços aos usuários, 
modularizando e abstraindo a visão do usuário. 
O uso de softwares, incluindo o sistema operacional, possibilita oferecer ao usuário uma visão daquilo 
que interessa a ele, ou seja, o software modulariza aquilo que o usuário vê e usa. 
O uso de um SO também permite abstrair não apenas o hardware como também rotinas de outros 
softwares, ou seja, é possível representar o funcionamento daquilo que está "abaixo" de um determinado 
aplicativo ou sistema operacional. Essas visões do usuário, abaixo ou acima, que representam conjuntos de 
serviços ou funções, podem ser representadas em um modelo chamado máquina de níveis, ou máquina de 
camadas, conforme mostrado na figura 2. 
Particularmente, a abstração do hardware, ou seja, qualquer camada acima do hardware, pode ser 
chamada de máquina virtual. 
 
Figura 2 – Máquina de níveis. Fonte: Adaptado de Machado, 2007. 
Histórico dos sistemas computacionais 
Um sistema operacional está intimamente ligado ao hardware do computador no qual ele é 
executado, estendendo o conjunto de instruções do computador e gerenciando seus recursos. Assim, o 
sistema operacional deve possuir grande conhecimento sobre o hardware, ao menos a partir do ponto de 
vista do programador. 
Os sistemas operacionais evoluíram gradualmente, e o processo temporal dessa evolução pode ser 
dividido em fases. 
A história dos sistemas operacionais é bastante relacionada à arquitetura de computadores. Sendo 
assim, veremos brevemente as várias gerações de computadores com o objetivo de entender as primeiras 
versões de sistemas operacionais. 
Primeira geração 
O período entre aproximadamente 1945 até 1955 corresponde ao surgimento da primeira geração 
dos computadores. Nessa época, a programação era feita em painéis de programação (figura 3), e os 
componentes de hardware eram mais primitivos, por exemplo, empregando válvulas (figura 4) na 
composição dos circuitos lógicos. 
Sistemas Operacionais 
Marcio Quirino - 12 
 
 
Figura 3 – Programação realizada em painéis físicos. Fonte: Produção Virtual UFPB. 
 
Figura 4 – Válvula. Fonte: Produção Virtual UFPB. 
Segunda geração 
Na segunda geração de computadores, compreendida entre aproximadamente 1955 até 1965, houve 
a adoção dos transistores no lugar das válvulas para a composição dos circuitos lógicos, e a aplicação de 
sistemas de computação em lote, como exemplificado na figura 5. O significado das etapas da figura 
encontra-se a seguir: 
a) Os programadores levavam os cartões para o leitor de cartões. 
b) O leitor de cartões gravava o lote de tarefas em fita. 
c) O operador levava a fita para o computador (7094) processar as informações. 
d) O computador executava o processamento. 
e) O operador levava a fita de saída para um dispositivo capaz de ler o conteúdo e enviar para a 
impressora. 
f) A impressora gerava as saídas.Sistemas Operacionais 
Marcio Quirino - 13 
 
 
Figura 5 - Imagem ilustrativa do sistema em lote (batch) da segunda geração. Fonte: Adaptado de Tanenbaum, 2010. 
Terceira geração 
Foi na terceira geração, compreendida entre 1965 a 1980, que o conceito de sistema operacional foi 
plenamente estabelecido, trazendo inovações como multiprocessamento, multiprogramação, time-sharing, 
spooling e memória virtual. Foi nessa geração que surgiram também os circuitos integrados (CIs) e o sistema 
operacional UNIX. 
Quarta geração 
Pode-se dizer que estamos na quarta geração de computadores, iniciada em 1980 e durando até o 
momento no qual este material foi escrito. Entretanto, alguns autores podem chamar os sistemas atuais de 
quinta geração. 
Nesse período, surgiram uma série de novidades e eventos relacionados aos computadores e aos 
sistemas operacionais, alguns dos quais exibidos na tabela 1. 
• Surgimento dos computadores pessoais 
• Integração em larga escala (LSI e VLSI) – Miniaturização e barateamento dos componentes 
eletrônicos 
• Intel produz seu primeiro microprocessador – Intel 4004 
• Intel 8080 – Primeiro microcomputador 
• 1976: Apple II (8 bits) 
• Surgimento da Microsoft 
• Redes distribuídas 
• Protocolos de redes 
• Redes locais 
• SO intimamente relacionados com o software de rede 
• Surgimento da linguagem Pascal e C 
• Surgimento do IBM PC – Intel 8088 de 16 bits com DOS (Disk Operating System) 
• Sistemas multiusuários foram impulsionados 
• Protocolos da internet TCP/IP 
• Surgimento das estações de trabalho 
• 1982: Surgimento da Sun Microsystems e das primeiras estações RISC 
• Surgimento das interfaces gráficas 
• Avanços de hardware, software e telecomunicações 
• Processadores e dispositivos de E/S mais rápidos e menores 
• Integração em ultra larga escala (ULSI) 
• Internet: Problemas de gerência, segurança e desempenho 
• Arquitetura Cliente – Servidor 
Sistemas Operacionais 
Marcio Quirino - 14 
 
• Software aberto (Open Source) 
• Demanda cada vez maior de processamento 
• Arquiteturas paralelas 
• Processamento distribuído 
• SO em celulares, tablets e outros 
MS Windows e UNIX 
Historicamente, existiram (e existem) diversos tipos e denominações de sistemas operacionais. 
Dentre esses vários, dois se destacam por serem bastante conhecidos e utilizados, e por ainda exercerem 
uma grande influência na evolução de todo o contexto tecnológico relacionado aos computadores: Windows 
e Unix. 
Windows 
MS-DOS 
A história do Windows começa com o MS-DOS (Disk Operating System), um sistema operacional de 
16 bits monoprogramável, monousuário e com interface de linha de comando, lançado pela Microsoft em 
1981 para o IBM-PC. 
MS Windows 1.0 
Em 1985, foi lançado o MS Windows 1.0, introduzindo uma interface gráfica para o MS-DOS. As 
versões seguintes continuaram mantendo o MS-DOS como núcleo de SO (tais como Windows 3.0, Windows 
95, Windows 98 e Windows Me). 
Windows NT 
Paralelo às versões baseadas no MS-DOS, o Windows NT foi lançado em 1993, sendo um sistema 
de 32 bits, com multitarefa preemptiva, multithread, memória virtual e suporte a múltiplos processadores 
simétricos, nas versões para desktop e servidores. O Windows NT possuía um núcleo completamente novo, 
mas oferecia compatibilidade parcial com aplicações legadas dos sistemas baseados em MS-DOS, e 
possuía a mesma interface gráfica das versões existentes. 
Windows 2000 
O Windows 2000 foi uma evolução do Windows NT 4, utilizando a mesma arquitetura interna, e novas 
funções, tais como o plug and play e o serviço de diretórios Active Directory. 
Windows XP 
A partir do Windows XP, lançado em 2001, a Microsoft começou a descontinuar as famílias DOS-
Windows e Windows NT/2000, integrando as duas linhas de sistemas operacionais. 
Outras versões 
Desde então, outras versões foram lançadas direcionadas para desktops (Windows Vista, Windows 
7, Windows 8, Windows 10) e servidores (Windows Server 2003, Windows Server 2008, Windows Server 
2012, Windows Server 2016, Windows Server 2019). 
Unix 
O Unix veio de outra vertente dos sistemas operacionais. Como já comentado anteriormente, uma 
das características da geração de computadores existentes na década de 1960 eram os sistemas batch. 
1965 
O MIT, a Bell Labs e a General Electric se uniram para desenvolver o MULTICS (MULTiplexed 
Information and Computing Service), um esforço para desenvolver um verdadeiro sistema operacional de 
tempo compartilhado. 
Sistemas Operacionais 
Marcio Quirino - 15 
 
1969 
Após a Bell Labs se retirar do projeto, Ken Thompson, que foi um dos pesquisadores envolvidos no 
projeto do MULTICS, desenvolveu sua própria versão em Assembly para um minicomputador PDP-7, que 
veio a se chamar UNICS (UNiplexed Information and Computing Service) e, mais para frente, Unix. Com o 
objetivo de torná-lo mais fácil de ser portado para outras plataformas, Thompson desenvolveu a linguagem 
B e reescreveu o código do sistema nessa nova linguagem. Thompson e Dennis Ritchie evoluíram a 
linguagem, criando o C. 
1973 
O Unix foi reescrito em C e portado para um minicomputador PDP-11. Depois disso várias 
universidades começaram a licenciar o Unix, como a Universidade de Berkeley, na Califórnia, que 
desenvolveu sua própria versão do sistema, chamada BSD (Berkeley Software Distribution), com várias 
melhorias, tais como a memória virtual, C shell, Fast File System, sockets, e o protocolo TCP/IP. 
1991 
O finlandês Linus Torvalds iniciou o desenvolvimento do Linux, baseado no Minix, uma variante do 
Unix desenvolvido pelo professor Andrew Tanenbaum, da Holanda, com fins educacionais. 
Atenção 
O Linux começou a evoluir com a ajuda de vários programadores voluntários. Assim, várias versões do Unix 
podem ser encontradas. 
A mais importante tentativa de unificação das várias versões do Unix foi feita pelo IEEE através do seu comitê 
POSIX (Portable Operating System Unix), que resultou em uma biblioteca padrão de chamadas e um conjunto de 
utilitários que todo sistema Unix deveria oferecer. 
2. Tipos de SO 
Identificar os tipos de Sistemas Operacionais. 
Tipos de Sistemas Operacionais 
Os sistemas operacionais podem ser classificados em: Sistemas operacionais monoprogramáveis 
/monotarefa; sistemas operacionais multiprogramáveis/multitarefa e sistemas com múltiplos processadores. 
 
Figura 6 – Tipos de sistemas operacionais. Fonte: Adaptado de Machado, 2007. 
Vejamos agora cada um deles: 
Sistemas Monoprogramáveis 
Nos sistemas monoprogramáveis (figura 7), também chamados de sistemas monotarefa, os 
principais módulos computacionais (processador, memória e periféricos) ficam alocados exclusivamente 
para a execução de um único programa, sendo que qualquer outra aplicação deve esperar para poder ser 
processada. 
Sistemas Operacionais 
Marcio Quirino - 16 
 
 
 Figura 7 –Sistemas monoprogramáveis/monotarefa. Fonte: Adaptado de Machado, 2007. 
Sistemas Multiprogramáveis ou Multitarefa 
Nos sistemas multiprogramáveis (figura 8), ou multitarefa, os recursos computacionais passam a ser 
compartilhados entre usuários e aplicações, permitindo que muitas aplicações compartilhem os mesmos 
recursos. 
Por exemplo, alguns aplicativos podem usar o processador enquanto um determinado programa 
aguarda o desfecho de um comando de leitura/gravação em mídia de armazenamento. 
 
Figura 8 – Sistemas multiprogramáveis/multitarefas. Fonte: Adaptado de Machado, 2007. 
Os sistemas multiprogramáveis podem ser classificados em sistemas batch, de tempo compartilhado 
ou de tempo real. O sistema operacional é responsável por gerenciar vários desses programas ao mesmo 
tempo, conforme ilustrado na figura 9. 
Sistemas Operacionais 
Marcio Quirino - 17 
 
 
Figura 9 – Classificação dos sistemas multiprogramáveis. Fonte: Adaptado de Machado, 2007. 
Um dos problemas que ocorriam nos sistemas monoprogramáveis é que havia um desperdício na 
utilização do processador (figura10). Por exemplo, enquanto uma leitura em disco era realizada, o 
processador permanecia ocioso, e o tempo de espera até que a leitura em disco fosse realizada era 
relativamente longo, pois as operações com dispositivos de E/S são muito lentas quando comparadas com 
a velocidade do processador para a execução de instruções. 
 
Figura 10 – Sistemas monoprogramáveis x sistemas multiprogramáveis. Fonte: Adaptado de Machado, 2007. 
Em sistemas multiprogramáveis, o processador é utilizado por diversos programas, ou processos, de forma 
concorrente, ou seja, quando um processo tem que fazer uma operação de E/S, outro processo pode utilizar o 
processador. 
A utilização da CPU como função da quantidade de processos carregados na memória 
simultaneamente é chamada grau de multiprogramação. A figura 11 apresenta um gráfico representando a 
utilização da CPU versus o grau de multiprogramação. 
 
Figura 11 – Utilização da CPU como função do número de processos na memória. Fonte: Adaptado de Machado, 2007. 
Atenção 
Pode-se perceber através da análise da figura 11 que, para a curva de “80% de espera de E/S”, se os processos 
passarem 80% do seu tempo esperando por dispositivos de E/S, pelo menos 10 processos devem estar na memória 
simultaneamente, para que a CPU desperdice menos de 10%. 
Sistemas Operacionais 
Marcio Quirino - 18 
 
 
Sistemas com múltiplos processadores 
Os sistemas com múltiplos processadores possuem dois ou mais processadores atuando juntos, 
oferecendo vantagens como: 
1. Escalabilidade 
✓ Aumenta a capacidade de processamento. 
2. Disponibilidade 
✓ Se um processador falhar, outro pode assumir a carga de trabalho. 
3. Balanceamento de carga 
✓ Distribuição da carga de trabalho entre os processadores. 
Em sistemas com múltiplos processadores, os processadores podem se comunicar de duas 
maneiras: Nos sistemas fortemente acoplados e sistemas fracamente acoplados. 
Sistemas fortemente acoplados 
Nos sistemas fortemente acoplados, os processadores compartilham somente a memória principal e 
os periféricos são gerenciados por um único sistema operacional. 
 
Figura 12 - Sistemas fortemente acoplados. Fonte: Adaptado de Machado, 2007. 
Os sistemas fortemente acoplados podem ser: 
Clique nas barras para ver as informações. 
SMP - Symmetric Multiprocessors 
• Os processadores acessam a memória uniformemente ao longo do tempo. 
NUMA - Non-Uniform Memory Access 
• Como existem conjuntos de processadores e memória principal, e um conjunto se conecta 
aos outros por meio de uma rede de interconexão, o tempo de acesso dos processadores 
à memória varia conforme a localização física. 
Sistemas Operacionais 
Marcio Quirino - 19 
 
Sistemas fracamente acoplados 
Já nos sistemas fracamente acoplados (figura 13), dois ou mais sistemas computacionais 
independentes (cada um possui o seu próprio sistema operacional e gerencia seus próprios recursos, como 
processador, memória e periféricos) estão conectados por linhas de comunicação. 
 
Figura 13 - Sistemas fracamente acoplados. Fonte: Adaptado de Machado, 2007. 
Os sistemas com múltiplos processadores também podem ser chamados "Sistemas Avançados de 
Processamento". Eles podem ser constituídos de computadores com vários processadores, processadores 
com vários núcleos e sistemas distribuídos. O S.O. deve estar adaptado para operar esses sistemas. 
Outras classificações dos sistemas operacionais 
Dentro desses mais de 50 anos de existência dos sistemas operacionais, existiu um desenvolvimento 
de uma grande variedade deles, alguns dos quais não foram bem conhecidos. 
Dentro dos tipos que existiram ao longo do tempo, um S.O. foi elaborado oferecendo um conjunto de 
serviços suportados. Por exemplo, alguns dos serviços que podem ser especificamente oferecidos pelos 
sistemas operacionais de computadores de grande porte são: 
1. O processamento simultâneo de muitas tarefas. 
2. O suporte ao manejo de grandes quantidades de E/S. 
3. O oferecimento dos serviços de processamento em lote (batch), de processamento de 
transações e de execução de tarefas em tempo compartilhado. 
Quanto aos serviços citados em (3), temos: 
Sistemas em lote 
• O sistema em lote (batch) processa tarefas de rotina sem a presença interativa do usuário. 
Por exemplo: Processamento de apólices de companhia de seguro; relatório de vendas 
de uma cadeia de lojas. 
Sistemas de processamento de transações 
• Os sistemas de processamento de transações administram grandes quantidades de 
pequenas requisições. Cada unidade de trabalho é pequena, mas o sistema precisa tratar 
centenas ou milhares delas por segundo. Por exemplo: Processamento de verificações 
em um banco ou em reservas de passagens aéreas. 
Sistemas de tempo compartilhado 
• Os sistemas de tempo compartilhado permitem que múltiplos usuários remotos executem 
suas tarefas simultaneamente no computador. Por exemplo: Realização de consultas a 
um banco de dados. 
Já os serviços de sistemas de tempo real possuem o tempo como parâmetro fundamental. Por 
exemplo: Linha de montagem de um carro. 
Sistemas Operacionais 
Marcio Quirino - 20 
 
Os sistemas de tempo real podem ser dos tipos: 
Sistema de tempo real crítico 
• As ações precisam ocorrer em determinados instantes. Exemplo: Processos industriais, 
aviônica, militares. 
Sistema de tempo real não crítico 
• O descumprimento de um prazo não causa dano permanente. Exemplo: Sistema de áudio 
digital, multimídia, telefones digitais. 
Comentário 
Alguns tipos de sistemas operacionais, assim como algumas das funcionalidades específicas relacionadas a 
cada tipo, podem deixar de existir, enquanto outros novos tipos e funcionalidades podem surgir, conforme acontece o 
avanço das tecnologias. 
Outra situação que acontece muitas vezes é certos tipos de SOs e de rotinas que já existiram em 
algum momento no passado caírem em desuso e voltarem a ser utilizadas no tempo presente. Tanenbaum 
(2010) diz que cada nova “espécie” de computador parece passar pelo mesmo desenvolvimento de seus 
ancestrais, tanto no que se refere ao hardware quanto ao software. Muitas vezes, uma alteração tecnológica 
torna alguma ideia obsoleta e ela desaparece rapidamente, mas outra mudança tecnológica pode reavivá-
la. 
Exemplo 
Um exemplo é o uso da memória cache nas CPUs quando se tornam mais velozes que as memórias. Se 
alguma nova tecnologia de memória tornar as memórias mais velozes que a CPU, as memórias caches irão 
desaparecer. E, no caso de uma nova tecnologia de CPU torná-las novamente mais rápidas que as memórias, as 
memórias caches reaparecerão. 
Para terminar, os sistemas operacionais variam quanto aos tipos de licenças, ou seja, o conjunto de 
ações que o usuário do SO pode ou não fazer: 
Software proprietário 
• Licenciado sob direitos legais exclusivos – copyright. 
• Usualmente o código-fonte total ou parcial não é disponibilizado para modificação por 
qualquer pessoa, apenas a fabricante possui o acesso. 
Software livre (free software) 
• Software livre se refere à liberdade dos usuários executarem, copiarem, distribuírem, 
estudarem, modificarem e aperfeiçoarem o software. 
• Por exemplo, a licença GNU da Free Software Foundation (FSF) possui as seguintes 
liberdades: 
• Liberdade nº 0: Executar o programa, para qualquer propósito. 
• Liberdade nº 1: Liberdade de estudar como o programa funciona, e adaptá-lo para as suas 
necessidades. Acesso ao código-fonte é um pré-requisito para esta liberdade. 
• Liberdade nº 2: Liberdade de redistribuir cópias de modo que você possa ajudar ao seu 
próximo. 
• Liberdade nº 3: Liberdade de aperfeiçoar o programa e liberar os seus aperfeiçoamentos, 
de modo que toda a comunidade se beneficie. Acesso ao código-fonte é um pré-requisito 
para esta liberdade. 
Software de código aberto (open source) 
• O código-fonte é disponibilizado por meio de uma licença de código aberto para 
modificação ou melhoria por qualquer pessoa. 
SistemasOperacionais 
Marcio Quirino - 21 
 
• Diferente das liberdades do software livre. 
• O termo "código aberto" foi criado pela OSI (Open Source Initiative). 
• Difere-se de um software livre por não respeitar as 4 liberdades definidas pela Free 
Software Foundation (FSF), compartilhadas também pelo projeto Debian em "Debian Free 
Software Guidelines (DFSG)". 
• Qualquer licença de software livre é também uma licença de código aberto (Open Source), 
mas o contrário nem sempre é verdade. 
• Exemplos de licenças de código aberto: 
✓ Apache License. 
✓ MIT License. 
✓ Mozilla Public License. 
✓ Common Development and Distribution License. 
✓ Eclipse Public License. 
3. Estrutura do SO: Kernel, System Calls, Modos de Acesso 
Compreender a estrutura do SO: Kernel, system calls, modos de acesso. 
Estrutura do SO: Kernel, System Calls, Modos de Acesso 
O sistema operacional é formado por um conjunto de rotinas que oferecem serviços aos usuários, às 
suas aplicações e ao próprio sistema. Esse conjunto de rotinas é denominado núcleo do sistema ou kernel, 
cuja localização na máquina de níveis está ilustrada na figura 14. 
 
Figura 14 - Kernel do SO na máquina de níveis. Fonte: Adaptado de Machado, 2007. 
Saiba mais 
O sistema operacional funciona com algumas particularidades quanto à execução das rotinas: 
• Tarefas não sequenciais, ou seja, as rotinas são executadas concorrentemente. 
• Sem ordem predefinida. 
• Eventos assíncronos. 
• Existem eventos relacionados ao hardware e eventos relacionados às tarefas internas do próprio SO. 
O núcleo do SO deve atuar considerando essas particularidades, e para isso implementa funções 
como: 
✓ Tratamento de interrupções e exceções. 
✓ Criação e eliminação de processos e threads. 
Sistemas Operacionais 
Marcio Quirino - 22 
 
✓ Sincronização e comunicação entre processos e threads. 
✓ Escalonamento e controle de processos e threads. 
✓ Gerência de memória. 
✓ Gerência do sistema de arquivos. 
✓ Gerência dos dispositivos de E/S. 
✓ Suporte a redes locais e distribuídas. 
✓ Contabilização do uso do sistema. 
✓ Auditoria e segurança do sistema. 
✓ Etc. 
A execução das rotinas no sistema operacional é controlada pelo mecanismo denominado system 
call (figura 15), ou chamada ao sistema, um mecanismo de proteção por software que garante a execução 
somente de rotinas previamente autorizadas. 
 
Figura 15 – System call. Fonte: Adaptado de Machado, 2007. 
System Calls 
Quando qualquer aplicação deseja chamar uma rotina do sistema operacional, ela aciona a system 
call. O sistema operacional verifica se a aplicação possui os privilégios suficientes para a execução da rotina 
desejada. Se não tiver, o sistema operacional impede o desvio para a rotina do sistema, e informa ao 
programa de origem que a operação não será executada. 
A system call é uma “porta de entrada” para o acesso ao núcleo do SO e aos seus serviços. Cada serviço 
possui uma system call associada, e cada SO possui seu próprio conjunto de chamadas, com nomes, parâmetros e 
formas de ativação específicas. 
Por exemplo, a chamada ao sistema "read" (figura 16) possui três parâmetros: 
 
Figura 16 – Chamada ao sistema "read". Fonte: Adaptado de Tanenbaum, 2010. 
Os passos para a realização da system call "read" estão ilustrados na figura 17: 
Sistemas Operacionais 
Marcio Quirino - 23 
 
 
Figura 17 - Passos para a realização da system call "read". Fonte: Adaptado de Tanenbaum, 2010. 
Observe uma breve descrição a seguir: 
1. Passos 1 a 3 
✓ O programa que chama read primeiramente armazena os parâmetros na pilha. 
2. Passos 4 e 5 
✓ Segue-se para a chamada real à rotina de biblioteca (passo 4) que, em geral, coloca o 
número da chamada de sistema em um local esperado pelo S.O., por exemplo, em um 
registrador (o passo 5). 
3. Passo 6 
✓ É executada uma instrução TRAP para passar do modo usuário para o modo núcleo, 
iniciando a execução em um determinado endereço no núcleo. 
4. Passo 7 
✓ O código do núcleo, iniciado após a instrução TRAP, verifica o número da chamada de 
sistema e despacha para a rotina correta de tratamento dessa chamada. 
5. Passo 8 
✓ É a execução da rotina de tratamento da chamada de sistema. 
6. Passos 9 e 10 
✓ Após o término dessa rotina, pode-se retornar o controle para a rotina de biblioteca no 
espaço do usuário, na instrução seguinte à instrução TRAP (passo 9), em geral do 
mesmo modo no qual são feitas as chamadas de rotina (passo 10). 
7. Passo 11 
✓ O programa do usuário deve limpar a pilha. O programa agora está liberado para fazer 
o que quiser. 
 
Sistemas Operacionais 
Marcio Quirino - 24 
 
Em geral, para qualquer situação, o funcionamento da system call (figura 18) consiste em: 
1. Realização da chamada ao sistema pela aplicação que deseja executar rotina(s). 
2. Processamento da solicitação pelo kernel. 
3. Retorno, para a aplicação solicitante, de uma resposta, com um estado de conclusão, 
indicando se houve algum erro. 
 
Figura 18 – Chamada a uma rotina de sistema. Fonte: Adaptado de Machado, 2007. 
Exemplo 
Um exemplo de conjunto de chamadas de sistema é o POSIX (Portable Operating System Interface for Unix), 
padrão internacional ISO/IEC/IEEE 9945 que foi uma tentativa de padronizar as system calls. 
O objetivo inicial foi unificar as diversas versões existentes do sistema operacional UNIX, permitindo um 
aplicativo utilizando o padrão POSIX teoricamente poder ser executado em qualquer SO que possua suporte. É 
incorporado, atualmente, pela maioria dos sistemas operacionais modernos. 
Já o conjunto de chamadas de sistemas Win32 é suportada desde o Windows 95. Cada nova 
versão do Windows traz novas chamadas que não existiam anteriormente, buscando não invalidar 
os programas existentes. 
A API Win32 possui um grande número de chamadas para gerenciar aspectos da interface gráfica 
(como janelas, figuras geométricas, textos, fontes de caracteres, caixas de diálogos, menus etc.). 
A API Win32 possui diferenças em relação ao POSIX. 
Uma delas é o desacoplamento das chamadas de biblioteca e das chamadas reais ao sistema, o que 
pode dificultar a identificação do que é uma chamada ao sistema, e do que é uma chamada de biblioteca no 
espaço do usuário. 
A API Win32 permite aos programadores acesso aos serviços do SO mesmo quando trabalhando 
em uma versão diferente com chamadas ao sistema modificadas. As chamadas Win32 chegam a milhares. 
A tabela 2 exibe algumas chamadas da API Win32 que correspondem, aproximadamente, às 
chamadas do UNIX. 
 
Sistemas Operacionais 
Marcio Quirino - 25 
 
UNIX Win32 Descrição 
fork CreateProcess Cria um novo processo 
waitpid WaitForSingleObject Pode esperar que um processo saia 
execve (nenhuma) CreateProcess = fork + execve 
exit ExitProcess Conclui a execução 
open CreateFile Cria um arquivo ou abre um arquivo existente 
close CloseHandle Fecha um arquivo 
read ReadFile Lê dados a partir de um arquivo 
write WriteFile Escreve dados em um arquivo 
iseek SetFilePointer Move o ponteiro do arquivo 
stat GetFileAttributesEx Obtém vários atributos do arquivo 
mkdir CreateDirectory Cria um novo diretório 
rmdir RemoveDirectory Remove um diretório vazio 
link (nenhuma) Win32 não dá suporte a links 
unlink DeleteFile Destrói um arquivo existente 
mount (nenhuma) Win32 não dá suporte a links 
umount (nenhuma) Win32 não dá suporte a links 
chdir SetCurrentDirectory Altera o diretório de trabalho atual 
chmod (nenhuma) 
Win32 não dá suporte à segurança (embora o NT 
suporte) 
kill (nenhuma) Win32 não dá suporte a sinais 
time GetLocalTime Obtém o tempo atual 
Tabela 2 – Chamadas da API Win32 que correspondem aproximadamente às chamadas do POSIX. Fonte: Adaptado de 
Tanenbaum, 2010. 
Podemos classificar os tipos de chamadas ao sistema em: Chamadas para o gerenciamento de 
processos, arquivos e diretórios. A Tabela 3 mostra alguns exemplos desses tipos de chamadas. 
Gerenciamento de processosChamada Descrição 
pid=fork() Cria um processo filho idêntico ao pai 
pid=waitpid(pid, &statloc, options) Espera que um processo filho seja concluído 
 
Gerenciamento de arquivos 
Chamada Descrição 
fd=open(file, how, ...0) Abre um arquivo para leitura, escrita ou ambos 
s=close(fd) Fecha um arquivo aberto 
n=read(fd, buffer, nbytes) Lê dados a partir de um arquivo em um buffer 
 
 
Sistemas Operacionais 
Marcio Quirino - 26 
 
Gerenciamento do sistema de diretório e arquivo 
Chamada Descrição 
s=mkdir(name, mode) Cria um novo diretório 
s=rmdir(name) Remove um diretório vazio 
s=mount(special, name, flag) Monta um sistema de arquivos 
 
Diversas 
Chamada Descrição 
s=chmod(name, mode) Altera os bits de proteção de um arquivo 
seconds=time(&seconds) Obtém o tempo decorrido desde 1 de janeiro de 1970 
Tabela 3 - Exemplos de tipos de chamadas ao sistema. Fonte: Adaptado de Tanenbaum, 2010. 
Modos de acesso 
As instruções executadas pelas aplicações podem ser dos tipos: 
1. Privilegiadas 
✓ Incluem as instruções que de algum modo podem comprometer o sistema. 
2. Não privilegiadas 
✓ São as instruções que não oferecem riscos ao sistema. 
As instruções podem acessar o sistema de dois modos: 
Modo kernel ou supervisor 
• Uma aplicação possui o modo de acesso supervisor quando é constituída de instruções 
privilegiadas. A aplicação pode executar o conjunto total de instruções. O modo kernel 
também protege a área do SO localizada na memória. 
Modo de acesso usuário 
• Uma aplicação possui o modo de acesso usuário quando é constituída de instruções não 
privilegiadas. 
Quando a aplicação chama a rotina do SO através da System Call, o sistema verifica se ela tem os 
privilégios necessários (autorizada pelo administrador do sistema). Se não possuir, o SO impede o desvio 
para a rotina do sistema através do mecanismo de proteção por software. 
Uma aplicação sempre deve executar com o processador em modo usuário. 
Você sabia 
Se uma aplicação tentar executar diretamente uma instrução privilegiada sem ser por intermédio de uma 
chamada à rotina do sistema, um mecanismo de proteção por hardware garantirá a segurança do sistema. O hardware 
do processador irá sinalizar com um erro. 
Arquiteturas de kernel 
Existem variações quanto à concepção da estrutura do núcleo do sistema operacional. As principais 
arquiteturas dos sistemas operacionais são: 
Arquitetura monolítica (mono-kernel) 
• Podemos comparar a arquitetura de núcleo monolítico com uma aplicação composta por 
vários módulos, que são compilados separadamente e depois linkados (ligados), constituindo 
um grande e único programa executável, no qual os módulos podem interagir livremente. Uma 
ilustração se encontra na figura 19. Nessa abordagem, o programa-objeto real do sistema 
Sistemas Operacionais 
Marcio Quirino - 27 
 
operacional é construído compilando todas as rotinas individualmente e depois juntando todas 
em um único arquivo-objeto usando o ligador (linker) do sistema. Todas as rotinas são visíveis 
umas às outras, não existindo, em essência, uma ocultação de informação. 
 
Figura 19 – Arquitetura monolítica. Fonte: Adaptado de Machado, 2007. 
Arquitetura de camadas 
• Nessa arquitetura, o sistema é dividido em várias camadas, que oferecem um conjunto de 
funções. Cada camada oferece suas funções para a camada imediatamente superior. Possui 
as vantagens de isolar as funções do SO, facilitando sua manutenção e depuração, e de criar 
uma hierarquia de níveis de modo de acesso, protegendo as camadas mais internas. Possui 
a desvantagem de poder ter o desempenho comprometido (a segregação implica em mais 
rotinas para a comunicação entre as camadas). 
Comentário 
Atualmente, a maioria dos SO comerciais para workstations, em geral, usam duas camadas. 
 
Figura 20 – Arquitetura de camadas. 
Sistemas Operacionais 
Marcio Quirino - 28 
 
 
Figura 21 – Arquitetura de camadas. Fonte: Adaptado de Tanenbaum, 2010. 
Máquina virtual ou virtual machine (VM) 
• Cria um nível intermediário entre o hardware e o sistema operacional, chamado de 
gerenciador de máquinas virtuais. Este nível possibilita a criação de máquinas virtuais 
independentes, sendo que cada uma oferece uma cópia virtual do hardware (virtualização), 
incluindo os modos kernel e usuário, as interrupções e dispositivos de E/S. 
O termo máquina virtual também pode ser definido como a ocultação de certas características computacionais 
através de uma camada de abstração. 
 
Figura 22 – Máquina virtual. Fonte: Adaptado de Machado, 2007. 
Comentário 
Nos últimos anos, as máquinas virtuais voltaram a ser bastante utilizadas. Muitas organizações executavam 
seus servidores em computadores separados às vezes com sistemas operacionais distintos. Com a virtualização, é 
possível executar todos eles na mesma máquina sem que uma falha em um servidor afete os outros. 
Quando os clientes alugam uma máquina virtual, uma mesma máquina física suporta muitas 
máquinas virtuais simultaneamente, logo poderão executar os sistemas operacionais e softwares que 
quiserem por uma parte do custo de um servidor dedicado. Pode-se usar a virtualização também para 
executar dois ou mais sistemas operacionais ao mesmo tempo. 
Para executar o software de máquina virtual em um computador, a CPU deve ser virtualizável. 
 
 
Sistemas Operacionais 
Marcio Quirino - 29 
 
Você sabia 
Em CPUs mais antigas, as tentativas de executar instruções não privilegiadas no modo usuário são ignoradas, 
o que impossibilitou a existência de máquinas virtuais nesse hardware. 
Essa situação deixou de existir ao substituir os hypervisors de tipo 1, executados diretamente no hardware, 
pelos hypervisors de tipo 2, executados como programas aplicativos na camada superior do sistema operacional, 
conhecida como sistema operacional hospedeiro. O hypervisor é o monitor de máquina virtual. 
O hypervisor de tipo 2 instala o sistema operacional hóspede em um disco virtual, que é apenas um arquivo 
grande no sistema de arquivos do sistema operacional hospedeiro. Quando o sistema operacional hóspede é 
inicializado, faz o mesmo procedimento que é feito no verdadeiro hardware, iniciando algum processo subordinado e 
depois uma interface gráfica. 
Arquitetura microkernel 
• Visa a tornar o núcleo do sistema operacional o menor e mais simples possível, 
disponibilizando no núcleo apenas os serviços do sistema que oferecem funções específicas, 
como gerência de arquivos, gerência de processos, gerência de memória e escalonamento. 
Os demais processos são executados fora do núcleo. 
É difícil de implementar na prática, sendo que usualmente é feita uma combinação híbrida, ou seja, do modelo 
de camadas com a arquitetura microkernel. 
 
Figura 23 – Arquitetura microkernel. Fonte: Adaptado de Machado, 2007. 
Atenção 
O princípio do microkernel é obter alta confiabilidade ao dividir o sistema operacional em pequenos módulos e 
bem definidos. Apenas o micronúcleo pode ser executado no modo núcleo. Os outros módulos são executados como 
processos de usuário comuns. 
Quando, por exemplo, há um erro em um driver de dispositivo executado como um processo de 
usuário separado, somente o componente correspondente é quebrado, enquanto que o sistema continua 
funcionando inteiramente. 
 
Exonúcleo 
• No lugar da clonagem da máquina real, como é no caso das máquinas virtuais, uma estratégia 
é dividi-la, ou seja, fornecer um subconjunto de recursos para cada usuário. 
 
Sistemas Operacionais 
Marcio Quirino - 30 
 
Exemplo 
Por exemplo, uma máquina virtual pode obter os blocos 0 a 1.023 do disco, outra os blocos 1.024 a 2.047 etc. 
O exonúcleo é um programa em execução em modo núcleo na camada mais inferior, que aloca 
recursos às máquinas virtuais e verifica as tentativas de uso para garantir que uma máquina não 
tente usar recursos de outra. 
A vantagem é que o exonúcleo poupa uma camada de mapeamento: Ao invés de cadamáquina 
virtual pensar que possui seu próprio disco (com blocos indo de 0 até o limite), fazendo com que o hypervisor 
mantenha tabelas para remapear os endereços de disco, com o exonúcleo, esse mapeamento não é mais 
necessário. 
Basta manter o registro de para qual máquina virtual foi atribuído qual recurso. 
4. Arquitetura, instalação do Linux e comandos básicos 
Analisar a arquitetura, instalação do Linux e comandos básicos 
Conceitos 
O Linux é um sistema operacional moderno e gratuito desenvolvido inicialmente em 1991 como um 
kernel pequeno e autocontido por Linus Torvalds, com os objetivos de ser baseado nos padrões UNIX e 
manter a compatibilidade com o mesmo. Sua história tem sido de colaboração por muitos usuários do mundo 
inteiro se comunicando principalmente através da Internet. 
O Linux é um sistema operacional dito “Unix-like”, por possuir comportamento similar ao do 
sistema operacional Unix (multitarefa e multiusuário). 
Saiba mais 
Uma distribuição Linux é constituída por uma coleção de aplicativos e o kernel (núcleo) do sistema operacional. 
As distribuições podem ser utilizadas por meio da instalação em disco no terminal do usuário, ou ainda por meio das 
distribuições do tipo live (oferecendo recursos mais limitados), que geralmente são executados a partir de dispositivos 
de armazenamento como discos removíveis, e carregados na memória RAM sem a necessidade de instalação no host. 
Vamos agora ver como podemos instalar o Linux para darmos os primeiros passos nesse sistema 
operacional. Para isso, iremos utilizar o Ubuntu, uma distribuição popular baseada no Debian, que servirá 
como base para as demonstrações exibidas neste módulo, especificamente a versão "Ubuntu desktop". 
Entretanto, você poderá optar por usar outras distribuições de sua escolha. O download poderá ser realizado 
na página do Ubuntu. 
 
Figura 24 – Logotipo do Ubuntu. Fonte: wikimedia. 
Cada versão do Ubuntu recebe uma numeração e um codinome, que seguem a lógica mostrada na 
tabela 4. 
Denominação da versão 20. 04 LTS Focal Fossa 
Significado Ano (2020) Mês (04 – abril) 
Long-Term Support (Suporte de longo prazo - 5 anos de 
suporte (atualizações)) 
Codinome 
Tabela 4 – Exemplo de numeração e um codinome do Ubuntu. Fonte: O Autor. 
Sistemas Operacionais 
Marcio Quirino - 31 
 
Faça o download do arquivo de imagem “iso" correspondente à versão atual do Ubuntu acessando 
a página do Ubuntu, conforme mostrado na figura 25. 
 
Figura 25 – Página para download do Ubuntu. Fonte: O Autor. 
Dica 
Você poderá melhorar a utilização do S.O. no VirtualBox instalando o “Adicionais para convidado”, acessando 
o menu “Dispositivos” -> “Inserir Imagem de CD dos Adicionais para Convidado”. O “CD” será automaticamente 
montado e deverá aparecer como execução automática. 
 
Figura 26 – Adicionais para convidado do VirtualBox. Fonte: O Autor. 
Estrutura de diretórios no Linux 
O Linux possui uma estrutura única de pastas, que partem de uma única raiz, como ilustrado na 
figura 27. 
Todos os dispositivos, internos ou externos, fixos ou removíveis, são montados em algum ponto 
abaixo da raiz. 
Sistemas Operacionais 
Marcio Quirino - 32 
 
 
Figura 27 – Estrutura de pastas do Linux. 
Atenção 
Existem regras para nomes de arquivos e pastas. O Linux é case-sensitive, ou seja, as letras MAIÚSCULAS e 
minúsculas fazem diferença no nome de um arquivo. Por exemplo, "texto", "Texto" e "TEXTO" são três arquivos 
distintos. Quando for escrever um caminho de diretórios, use o separador "/". Exemplo: /tmp/Texto.txt. 
As principais pastas e seus significados resumidos estão mostrados na tabela 5. 
/ Pasta Raiz /usr Programas de Usuário 
/bin Executáveis Binários /home Pasta Pessoal 
/sbin Sistema Binário /boot Arquivos de Inicialização 
/etc Arquivos de Configuração /lib Bibliotecas do Sistema 
/dev Arquivos de Dispositivos /opt Aplicações Opcionais 
/proc Informação de Processo /mnt Pasta de Montagem 
/var Arquivos Variáveis /media Dispositivos Removíveis 
/tmp Arquivos Temporários /srv Serviço de Dados 
Tabela 5 – Diretórios e seus significados. Fonte: O Autor. 
O Super Usuário é um usuário especial predefinido, com poderes especiais de administração. No 
Windows é chamado de administrador (administrator), e no Linux (Unix) é denominado root. 
Comandos do Linux 
A seguir, serão mostrados os comandos básicos para o terminal do Linux. No Ubuntu Desktop, clique 
no ícone "mostrar aplicativos" na barra da lateral esquerda, digite "term" na caixa de pesquisa, e abra o 
terminal. 
O terminal (ou prompt de comando) será aberto, conforme a figura 30. Veja o significado da linha de 
comandos: 
teste@teste-VirtualBox:~$ 
teste: Usuário 
teste-VirtualBox: Nome da máquina 
~$: Significa que o usuário está na sua pasta pessoal em /home ("/home/usuário") 
Sistemas Operacionais 
Marcio Quirino - 33 
 
 
Figura 30 – Terminal. Fonte: O Autor. 
Saiba mais 
Veja uma lista com os Comandos básicos para uso via terminal. 
Comandos básicos para uso via terminal 
• pwd → Mostra o diretório no qual o usuário está no momento. 
• sudo <comando> → Permite que o usuário execute comandos como ‘root’, sem ter que usar a 
conta de ‘root’. 
• su →Permite que o usuário entre no modo Super Usuário. Aconselha-se usar esse comando 
somente quando for necessário, não sendo aconselhado usar o modo super usuário para 
executar suas ações de rotina. Configure primeiramente usando o comando sudo passwd para 
poder usar o comando su. A linha de comandos, então, ficará da seguinte maneira: 
root@teste-VirtualBox:/# 
root: Usuário ‘root’ 
teste-VirtualBox: Nome da máquina 
/#: Usuário que possui nível de acesso privilegiado a partir da raiz do sistema 
Depois que tiver realizado o procedimento que demandou o uso da conta ‘root’, volte para o 
usuário padrão digitando exit. 
• cd [opções] <caminho> → Navega entre as pastas do sistema. 
a. cd .. ➔ Acessa um diretório de nível acima do atual. 
b. cd / ➔ Vai para o diretório raiz. 
c. cd ~ ➔ Vai para o seu diretório pessoal. 
d. cd – ➔ Volta para o diretório no qual o usuário se encontrava antes de mudar. 
• ls → Lista arquivos e diretórios. A opção –a mostra arquivos ocultos e a opção –l mostra mais 
informações (detalhes). 
Exemplo: “ls” ou “ls –l” ou “ls –a” ou “ls –la” 
• Símbolo ~ → Representa o diretório pessoal (home) do usuário, também chamado de diretório 
de login. 
Exemplos: 
a. ~teste → Caminho para a pasta pessoal do usuário ‘teste’ 
b. cd ~teste 
(a) Acessa a pasta pessoal do usuário ‘usuário’. 
c. ls ~teste/documentos 
(a) Lista os arquivos na pasta ‘documentos’, contida na pasta pessoal do usuário. 
• cat → Exibe o conteúdo de um arquivo na tela do terminal. 
Exemplo: “cat /etc/resolv.conf” 
Sistemas Operacionais 
Marcio Quirino - 34 
 
• head [opção] → Exibe o conteúdo do início de um arquivo. 
a. -n → Exibe as n primeiras linhas 
(a) Ex.: “head -3 /etc/hosts” 
• tail → Exibe o conteúdo do final de um arquivo. 
a. -n → Exibe as n primeiras linhas 
(a) Exemplo: “tail -3 /etc/hosts” 
• clear → Limpa a tela do terminal. 
• cp → Copia arquivos. 
a. Exemplo: “cp arquivo1 arquivo2” 
(a) Observação: Origem e destino no mesmo diretório. 
b. Ex.: “cp arquivo1 /dir/arquivo2” 
(a) Obs.: Destino em diretório diferente. 
c. Exemplo: “cp /dir/arquivo1 /dir/arquivo2” 
(a) Observação: Origem e destino em diretórios diferentes. 
• mv → Move arquivos. 
a. Exs.: “mv /home/teste/resolv.conf /tmp/” 
b. “mv /home/teste/resolv.conf /tmp/” 
• rm → Remove arquivos/diretórios. Opção –rf remove de forma recursiva e forçada (muito cuidado 
ao usar, pois poderá apagar tudo acidentalmente). 
a. Exemplo: “rm /tmp/musica.mp3” 
• mkdir → Cria um diretório. 
a. Exemplo: “mkdir /home/teste/musicas” 
• rmdir → Remove um diretório, apenas se ele estiver vazio. 
a. Exemplo: “rmdir /home/teste/musicas” 
• man <comando> → Exibe uma página de instruções para um comando ou arquivo de 
configuração.a. Exemplo: “man head”. 
• exit ou logout → Sai da sessão atual, ou realiza o logout do usuário. 
a. Pode-se encerrar a sessão também com a combinação de teclas CTRL+D. 
• reboot → Reinicia a máquina. 
• poweroff ou halt → Desliga a máquina de forma segura. 
• shutdown <opção> <quando> [Mensagem] → Reinicia ou desliga a máquina. 
a. Exemplo: ‘shutdown –h +5 “Aviso: Servidor desligando”’: O servidor desligará em 5 
minutos e será enviada a mensagem aos demais usuários conectados. 
b. Lembre-se de usar “sudo”. 
• date → Mostra a data e hora do sistema. 
a. Exemplo: “sudo date 082013502020”: Altera a data e hora para 13:50h de 20/08/2020. 
• history → Exibe o histórico de comandos já digitados no terminal. 
• touch <nome> → Cria o arquivo <nome> vazio. Se o arquivo já existe, sua hora é atualizada. 
• apt → Gerenciador de pacotes do Ubuntu, evolução do Apt-Get. 
a. apt update ➔ Atualiza a lista de fontes. 
b. apt install <nome_pacote> ➔ Instala um novo pacote. 
c. apt remove <nome_pacote> ➔ Remove um pacote. 
d. apt upgrade ➔ Atualiza todos os pacotes instalados. 
e. apt full-upgrade➔ Atualiza o sistema todo para uma nova versão. 
Alguns aplicativos são obtidos na forma de código-fonte aberto, implicando na necessidade de 
compilação do código. Os passos gerais para compilação de código-fonte são: 
✓ Realizar o download do arquivo-fonte (por exemplo, .tar.gz). 
✓ Descompactar o arquivo-fonte. 
Sistemas Operacionais 
Marcio Quirino - 35 
 
✓ Acessar o diretório contendo os arquivos do código-fonte. 
✓ Executar os seguintes comandos: 
./configure 
make 
make install 
Considerações finais 
O sistema operacional surgiu com o objetivo de tornar o uso do computador mais fácil e conveniente 
para o usuário. 
É muito importante o entendimento da ideia de abstração em sistemas de computação. O sistema 
operacional é um conjunto de rotinas que tem o objetivo de abstrair as camadas inferiores e o hardware, no 
modelo de máquina de camadas. Essas rotinas em geral constituem o núcleo do sistema operacional, 
embora algumas rotinas possam ser executadas no espaço do usuário, conforme varia a estrutura do núcleo 
do sistema operacional. 
Existem (e existiram) diversos sistemas operacionais ao longo da história. Um dos mais conhecidos 
e bastante utilizado é o Linux, que conta com uma enorme gama de distribuições à disposição dos usuários. 
Referências 
MACHADO, F. B.; MAIA, L. P. M. Arquitetura de sistemas operacionais. 4. ed. Rio de Janeiro: LTC, 
2007. 
MACHADO, F. B.; MAIA, L. P. M. Arquitetura de sistemas operacionais. 5. ed. Rio de Janeiro: LTC, 
2013. 
MACHADO, F. B.; MAIA, L. P. M. Arquitetura de sistemas operacionais – Material Suplementar para 
Acompanhar. 5. ed. Rio de Janeiro: LTC, 2013. 
SILBERSCHATZ, A. Fundamentos de sistemas operacionais – Princípios básicos. 1. ed. Rio de 
Janeiro: LTC, 2013. 
TANENBAUM, A. S. Sistemas Operacionais Modernos. 3. ed. São Paulo: Pearson, 2010. 
TANENBAUM, A. S.; BOS, H. Sistemas Operacionais Modernos. 4. ed. São Paulo: Pearson, 2016. 
Explore+ 
Para saber mais sobre os assuntos tratados neste tema, pesquise na internet: 
Comunidade Open Source ‒ Open Source (Código Aberto). 
GuiaFoca. 
Linux From Scratch! 
O Sistema Operacional GNU e o Movimento de Software Livre, GNU. 
Open Source Initiative, Opensource. 
Para saber mais sobre os assuntos tratados neste tema, pesquise na internet: 
Crash Course Ciência da Computação, Episódio 2, YouTube. 
Dentro do seu computador ‒ Bettina Bair, YouTube. 
 
Sistemas Operacionais 
Marcio Quirino - 36 
 
Processos e Gerencia de Processador 
Definição 
Definição de processos e threads e da forma como esses elementos devem ser estruturados para a 
construção de sistemas eficientes. 
Propósito 
Atualmente, até os mais simples dispositivos contam com a capacidade de multiprocessamento. Os 
sistemas operacionais, acompanhando o rápido desenvolvimento da tecnologia, fornecem mecanismos que 
possibilitam a construção de sistemas concorrentes que buscam tirar o máximo proveito desta capacidade. 
Saber explorar esta possibilidade é fundamental para a formação de profissionais habilitados a resolverem 
os desafios demandados por sistemas que buscam alto desempenho. 
Preparação 
Antes de iniciar o conteúdo deste tema, é desejável ter acesso a um computador (ou máquina virtual) 
com Linux instalado. Para os exemplos deste tema, foi utilizado o Ubuntu Desktop 20.04 LTS. 
Introdução 
Neste tema, estudaremos os conceitos de processos e como eles são utilizados para tirar proveito 
da capacidade de multiprocessamento dos equipamentos atuais. Para isso, veremos a criação de 
subprocessos e como eles se comunicam. Estudaremos também o funcionamento dos threads, que são 
linhas de execução concorrentes dentro de um processo, fornecendo ao programador/desenvolvedor os 
mecanismos necessários para permitir a concorrência dentro de um processo. 
Por fim, destacaremos os cuidados que devemos ter ao desenvolver sistemas que acessam dados 
compartilhados e os mecanismos que permitem o desenvolvimento seguro de tais aplicações. 
1. Conceitos de processos 
Descrever os conceitos de processos 
Conceitos 
Antes de iniciar 
Neste tema, você verá alguns exemplos de funcionamento de programas e comandos. Para o 
desenvolvimento dos exemplos, foi utilizado o Sistema Operacional Ubuntu Desktop 20.04 LTS, porém você 
pode utilizar o Linux de sua preferência. O esperado é que não haja diferença de utilização entre as várias 
distribuições Linux. 
Os programas utilizados como exemplo foram desenvolvidos em Linguagem C, uma linguagem 
clássica para o desenvolvimento de sistemas operacionais. O objetivo dos exemplos é permitir que você 
possa ver a utilização prática dos conceitos estudados no tema. 
1. Instalando o compilador 
✓ Para instalar o compilador de Linguagem C no Ubuntu, assim como em qualquer 
distribuição Linux derivada do Debian, basta executar no shell os comandos: 
sudo apt-get update 
sudo apt-get install gcc 
 
Sistemas Operacionais 
Marcio Quirino - 37 
 
2. Compilando 
✓ Para compilar um programa chamado prog.c basta entrar no shell, no diretório onde se 
encontra o programa, e executar o comando: 
gcc prog.c 
3. Compilando especificando a saída 
✓ Para compilar um programa e escolher o nome do arquivo executável que será gerado, 
utilize o parâmetro -o. Por exemplo, para compilar o programa prog.c e gerar como saída 
um arquivo executável prog, utilize o comando: 
gcc prog.c -o prog 
4. Executando o programa 
✓ Para executar o programa prog que acabou de ser compilado, execute o comando: 
./prog 
Modelo de processo 
Os primeiros sistemas permitiam a execução de apenas um programa de cada vez, que deveria ter 
o controle completo do sistema e acesso a todos os seus recursos. Os sistemas atuais permitem que 
diversos programas sejam carregados na memória e executados simultaneamente. 
Essa evolução tornou necessário um controle maior na divisão de tarefas dos vários programas, 
resultando na noção de processo. 
Em um sistema multiprogramável, a unidade central de processamento (UCP) alterna entre 
processos, dedicando um pouco de seu tempo a cada um, dando a ilusão de paralelismo. Este esquema 
costuma ser chamado de pseudoparalelismo. 
Sistema multiprogramável 
Sistema que permite a execução de mais de um programa ao mesmo tempo. 
Neste modelo, todo software executado no computador é organizado em processos sequenciais, 
também chamado de processos. O modelo de processos foi desenvolvido para tornar o paralelismo mais 
fácil de tratar. 
Um processo é um programa em execução, incluindo os valores atuais dos registradores e variáveis, 
assim como seu espaço de endereçamento. Um programa por si só não é um processo, mas uma entidade 
passiva. Um processo é uma entidade ativa, com um contador de instruções e um conjunto de 
registradores a ele associado. 
Espaço de endereçamento 
Conjunto de endereços de memóriaque um processo pode acessar. 
Contador de instruções 
Registrador de uma unidade central de processamento que indica qual é a posição atual na sequência de 
execução de um processo. Dependendo dos detalhes da arquitetura, ele armazena o endereço da instrução que está 
sendo executada ou o endereço da próxima instrução. 
Atenção 
Embora dois processos possam estar associados a um mesmo programa, são duas sequências de execução 
distintas. 
Conceitualmente, cada processo tem sua própria UCP. Com a UCP alternando entre os processos, 
a velocidade com que um processo executa não será uniforme. 
Sistemas Operacionais 
Marcio Quirino - 38 
 
 
Exemplo de sistema de tempo compartilhado com 4 processos concorrentes. 
Na figura anterior, vemos um exemplo de um sistema no qual são executados os processos A, B, C 
e D. O processo A é executado até o instante t1, quando para, e o processo B é colocado em execução até 
o instante t2. Os processos alternam suas execuções até que, no instante t4, o processo D para de executar 
e o processo A retoma sua execução. 
Como os processos alternam suas execuções de forma muito rápida, o usuário tem a ilusão de que 
os processos estão realmente sendo executados ao mesmo tempo. 
Criação e encerramento de processos 
Sistemas operacionais precisam criar processos durante sua operação. 
Quatro eventos principais fazem com que processos sejam criados: 
1. Inicialização do sistema. 
2. Execução de uma chamada de sistema de criação de processo por um processo em 
execução. 
3. Solicitação de um usuário para criar um processo. 
4. Início de uma tarefa em lote. 
Quando um sistema operacional é inicializado, uma série de processos são criados. Alguns são 
processos de primeiro plano (interagem com usuários), enquanto outros operam no segundo plano 
(background) e não estão associados a usuários em particular. Processos que ficam em segundo plano para 
lidar com algumas atividades, como e-mail, páginas da web, notícias, impressão, são chamados de 
daemons. 
Além dos processos criados durante a inicialização do sistema, outros também podem ser criados. 
Muitas vezes, um processo em execução emitirá chamadas de sistema para criar um ou mais processos 
para ajudá-lo em seu trabalho. Criar processos novos é particularmente útil quando o trabalho a ser feito 
pode ser facilmente formulado em termos de vários processos relacionados. Em um multiprocessador, por 
exemplo, cada processo pode ser executado em uma UCP, fazendo com que a tarefa seja realizada mais 
rapidamente. 
Multiprocessador 
Sistema com mais de um processador nos quais os processadores compartilham uma memória comum. 
Em sistemas interativos, os usuários podem começar um programa digitando um comando ou 
clicando duas vezes sobre um ícone. Cada uma dessas ações inicia um novo processo e executa o programa 
selecionado. 
Tarefas em lote costumam ser executadas em grandes sistemas. As tarefas são submetidas ao 
sistema e, quando o sistema operacional tem os recursos necessários para executar outra tarefa, cria um 
processo e executa a próxima tarefa a partir da fila de entrada. 
 
Sistemas Operacionais 
Marcio Quirino - 39 
 
Atenção 
Em todos esses casos, um novo processo é criado por outro já existente, executando uma chamada de sistema 
de criação de processo. O que esse processo faz é executar uma chamada de sistema para criar o processo. 
No Linux, a chamada de sistema mais comum para a criação de processos é a fork(). Essa chamada 
cria um processo idêntico ao processo que a chamou. Após a fork(), os dois processos, o pai e o filho, têm 
a mesma imagem de memória, as mesmas variáveis de ambiente e os mesmos arquivos abertos. 
O código a seguir, em Linguagem C, exemplifica a criação de um novo processo com a chamada de 
sistema fork(). 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 
 
int main() { 
int resultado, pid, ppid; 
resultado = fork(); 
if (resultado < 0) 
printf("Algo deu errado!!!\n"); 
pid = getpid(); 
if (resultado == 0) { 
ppid = getppid(); 
printf("Eu sou o processo filho, meu PID é %d e meu pai tem PID=%d.\n", pid, 
ppid); 
} 
if (resultado > 0) { 
printf("Eu sou o processo pai, meu PID é %d e meu filho tem PID=%d.\n", pid, 
resultado); 
waitpid(resultado, NULL, 0); 
} 
} 
Quando fork() é executada, o resultado do processamento é armazenado na variável “resultado”. O 
processo pai (que fez a chamada) receberá na variável “resultado” o PID do processo filho, enquanto o 
processo filho receberá na variável “resultado” o valor 0. Assim, para saber quem é o processo pai e quem 
é o processo filho, é necessário verificar o valor em “resultado”. 
1. De início, verifica-se a ocorrência de algum erro na criação do processo filho. Caso tenha 
ocorrido um erro, “resultado” receberá um valor negativo. 
2. A seguir, o comando “pid = getpid();” obtém o PID do processo corrente. 
3. Então, o processo verifica o valor de “resultado”. Se for zero, é o processo filho que está 
executando e, nesse, caso o processo executa “ppid = getppid();” para obter o PID do 
processo pai. Se o valor de “resultado” for maior que zero, significa que quem está 
executando é o processo pai. Ambos (pai e filho) mostram na tela os respectivos PID. 
4. Por fim, o processo pai executa a chamada de sistema “waitpid(resultado, NULL, 0);” para, 
antes de terminar, aguardar o término da execução do filho. 
Quando o fork() é utilizado para a criação de um processo que executará o código de outro programa, 
a chamada de sistema execve() deve ser utilizada para que o processo filho mude sua imagem de memória 
e execute o novo programa. 
O código a seguir ilustra a utilização de execve(). Nele, o processo pai cria três processos filhos em 
sequência. O primeiro coloca em execução uma calculadora, o segundo, o editor de textos gedit, e o terceiro, 
o utilitário xeyes. 
 
Sistemas Operacionais 
Marcio Quirino - 40 
 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 
 
int main(int argc, char **argv, char* envp[]) { 
int pid, i; 
 
for (i=1; i<=3; i++) { 
pid = fork(); 
if (pid < 0) { 
printf("Algo deu errado!!!\n"); 
return 0; 
} 
if (pid == 0) { // Processo filho 
if (i == 1) 
execve("/usr/bin/xcalc", argv, envp); 
if (i == 2) 
execve("/usr/bin/gedit", argv, envp); 
if (i == 3) 
execve("/usr/bin/xeyes", argv, envp); 
} 
else // Processo pai 
waitpid(pid, NULL, 0) 
} 
} 
Após ter executado sua tarefa, o novo processo terminará devido a uma das seguintes condições: 
Saída normal (voluntária) 
A maioria dos processos termina por terem realizado o seu trabalho. Quando isto ocorre, o processo executa 
uma chamada para dizer ao sistema operacional que ele terminou e para que o sistema possa tomar as providências 
necessárias ao seu encerramento. 
Erro fatal (involuntário) 
O processo também pode terminar quando descobre um erro fatal. Ele pode solicitar ao usuário uma nova 
entrada de dados ou simplesmente encerrar sua execução de maneira similar à saída normal. 
Saída por erro (voluntária) 
Outra razão para o término é um erro causado pelo processo, muitas vezes decorrente de um erro de programa. 
Exemplos incluem executar uma instrução ilegal, referenciar uma memória não existente ou dividir por zero. 
Morto por outro processo (involuntário) 
A quarta razão pela qual um processo pode ser finalizado é a execução de uma chamada de sistema dizendo 
ao sistema operacional para matar outro processo. Para um processo matar outro, é necessário autorização. 
Em alguns sistemas, quando um processo é finalizado, todos os processos que ele criou são 
finalizados também. Nem o Linux nem o Windows funcionam desta forma. 
Hierarquia de processos 
Em alguns sistemas, quando um processo cria outro, o processo pai e o processo filho continuam 
associados. O processo filho pode criar mais processos, formando uma hierarquia de processos. No Linux, 
um processo e todos os seus filhos edemais descendentes formam um grupo de processos. 
No Linux, um processo especial chamado systemd (ou init, dependendo da versão) está presente na 
imagem de inicialização do sistema. É o primeiro processo a ser executado e é responsável por iniciar a 
execução dos demais processos do sistema operacional. Cada um desses processos pode iniciar mais 
processos. Desse modo, todos os processos no Linux pertencem a uma única árvore, com o systemd (ou 
init) em sua raiz. 
Sistemas Operacionais 
Marcio Quirino - 41 
 
A imagem a seguir exemplifica a árvore de processos em um sistema Linux por meio da execução 
do comando “pstree”. 
systemd-+-ModemManager---2*[{ModemManager}] 
|-NetworkManager---2*[{NetworkManager}] 
|-VBoxService---8*[{VBoxService}] 
|-accounts-daemon---2*[{accounts-daemon}] 
|-acpid 
|-avahi-daemon---avahi-daemon 
|-colord---2*[{colord}] 
|-cron 
|-cups-browsed---2*[{cups-browsed}] 
|-cupsd 
|-dbus-daemon 
|-gdm3-+-gdm-session-wor-+-gdm-wayland-ses-+-gnome-session-b---3*[{gnome-session-b}] 
| | | `-2*[{gdm-wayland-ses}] 
| | `-2*[{gdm-session-wor}] 
| `-2*[{gdm3}] 
|-2*[kerneloops] 
|-login---bash---pstree 
|-networkd-dispat 
|-polkitd---2*[{polkitd}] 
|-rsyslogd---3*[{rsyslogd}] 
|-rtkit-daemon---2*[{rtkit-daemon}] 
|-snapd---8*[{snapd}] 
|-switcheroo-cont---2*[{switcheroo-cont}] 
|-systemd---(sd-pam) 
|-systemd-+-(sd-pam) 
| |-at-spi-bus-laun-+-dbus-daemon 
| | `-3*[{at-spi-bus-laun}] 
| |-at-spi2-registr---2*[{at-spi2-registr}] 
| |-dbus-daemon 
| |-gjs---4*[{gjs}] 
| |-gnome-keyring-d---3*[{gnome-keyring-d}] 
| |-gnome-session-b---3*[{gnome-session-b}] 
| |-gnome-session-c---{gnome-session-c} 
| |-gnome-shell-+-Xwayland 
| | |-ibus-daemon-+-ibus-engine-sim---2*[{ibus-engine-sim}] 
| | | |-ibus-memconf---2*[{ibus-memconf}] 
| | | `-2*[{ibus-daemon}] 
| | `-6*[{gnome-shell}] 
| |-goa-daemon---3*[{goa-daemon}] 
| |-goa-identity-se---2*[{goa-identity-se}] 
| |-gsd-a11y-settin---3*[{gsd-a11y-settin}] 
| |-gsd-color---3*[{gsd-color}] 
| |-gsd-keyboard---3*[{gsd-keyboard}] 
| |-gsd-media-keys---3*[{gsd-media-keys}] 
| |-gsd-power---3*[{gsd-power}] 
| |-gsd-print-notif---2*[{gsd-print-notif}] 
| |-gsd-printer---2*[{gsd-printer}] 
| |-gsd-rfkill---2*[{gsd-rfkill}] 
| |-gsd-smartcard---4*[{gsd-smartcard}] 
| |-gsd-sound---3*[{gsd-sound}] 
| |-gsd-usb-protect---3*[{gsd-usb-protect}] 
| |-gsd-wacom---3*[{gsd-wacom}] 
| |-gsd-wwan---3*[{gsd-wwan}] 
| |-gsd-xsettings---3*[{gsd-xsettings}] 
| |-gvfs-afc-volume---3*[{gvfs-afc-volume}] 
| |-gvfs-goa-volume---2*[{gvfs-goa-volume}] 
| |-gvfs-gphoto2-vo---2*[{gvfs-gphoto2-vo}] 
| |-gvfs-mtp-volume---2*[{gvfs-mtp-volume}] 
| |-gvfs-udisks2-vo---3*[{gvfs-udisks2-vo}] 
| |-gvfsd---2*[{gvfsd}] 
| |-gvfsd-fuse---5*[{gvfsd-fuse}] 
| |-ibus-portal---2*[{ibus-portal}] 
| |-ibus-x11---2*[{ibus-x11}] 
| |-pulseaudio---3*[{pulseaudio}] 
| |-tracker-miner-f---4*[{tracker-miner-f}] 
| `-xdg-permission----2*[{xdg-permission-}] 
Sistemas Operacionais 
Marcio Quirino - 42 
 
|-systemd-journal 
|-systemd-logind 
|-systemd-resolve 
|-systemd-timesyn---{systemd-timesyn} 
|-systemd-udevd 
|-udisksd---4*[{udisksd}] 
|-unattended-upgr---{unattended-upgr} 
|-upowerd---2*[{upowerd}] 
|-whoopsie---2*[{whoopsie}] 
`-wpa_supplicant 
Estados de processos 
Eventualmente, um processo que está em execução necessita parar momentaneamente sua 
execução por estar aguardando uma informação ainda não disponível ou porque já foi executado por muito 
tempo e precisa liberar a UCP para outro processo. 
Um processo pode transitar por diferentes estados, que dependem do sistema operacional. De forma 
geral, podemos dizer que um processo pode estar nos estados novo, executando, pronto, bloqueado ou 
terminado. 
 
Quando um processo é criado, ele se inicia no estado novo. O processo já existe, mas ainda precisam 
ser tomadas algumas providências pelo sistema operacional para que o processo possa iniciar sua 
execução. Quando tudo está pronto, o processo faz a transição 1 e muda para o estado pronto. 
O processo reúne todas as condições para ser executado quando está no estado pronto, faltando 
apenas que o processador fique disponível para sua execução. Quando um processador fica disponível e o 
processo é selecionado para execução, ele faz a transição 2 e vai para o estado executando. 
No estado executando, o processo tem suas instruções executadas pelo processador e três coisas 
podem acontecer: 
1. Etapa 01 
✓ A primeira delas é o processo ser executado por muito tempo. Então, o sistema 
operacional interrompe momentaneamente a execução do processo para colocar outro 
em seu lugar, ocorrendo a transição 3, que leva o processo de volta ao estado pronto, 
no qual aguardará nova oportunidade de execução. 
2. Etapa 02 
✓ Pode ocorrer ainda de o processo solicitar uma operação de entrada e saída e ter de 
aguardar a conclusão da operação, que costuma ser demorada quando comparada à 
capacidade de processamento do processador de um computador. Nesse caso, ocorre 
a transição 4, e o processo vai para o estado bloqueado. 
3. Etapa 03 
✓ Por último, o processo pode encerrar sua execução, realizando a transição 6 e indo para 
o estado terminado. 
O processo que vai para o estado bloqueado permanece nele até que seja concluída a operação que 
aguardava. Quando isso ocorre, o processo passa pela transição 5 e vai para o estado pronto até ser 
novamente selecionado para execução. 
Sistemas Operacionais 
Marcio Quirino - 43 
 
Atenção 
O estado terminado é para os processos que não serão mais executados. Quando está neste estado, o sistema 
operacional deve providenciar a desalocação dos recursos que ainda estejam alocados ao processo. Somente após a 
desalocação de todos os recursos, o processo deixa de existir no sistema. 
Para implementar o modelo de processos, o Linux mantém uma tabela de processos, com uma 
entrada por processo. Esta entrada é chamada de Bloco de Controle de Processo – BCP (Process Control 
Block – PCB) e contém todas as informações do processo. Algumas entradas do BCP são: 
✓ Estado do processo 
✓ Prioridade do processo 
✓ Número do processo 
✓ Registradores da UCP 
✓ Informações relativas ao gerenciamento de memória 
✓ Informações de contabilidade 
✓ Informações sobre operações de E/S 
Essa visão dá origem ao seguinte modelo: 
 
O nível mais baixo do sistema operacional é o escalonador (também conhecido como agendador). 
Ele cuida do gerenciamento de interrupções e dos detalhes de como iniciar e parar processos. Também 
costuma ser muito pequeno. 
Um processo passa pelas várias filas de seleção durante sua execução. Cabe ao escalonador 
selecionar processos destas filas e decidir qual será o próximo a ser executado. 
O escalonador é chamado com muita frequência. Um processo pode ser executado por apenas 
alguns milissegundos (ms) e ter de esperar por ter feito uma requisição de E/S. O escalonador costuma ser 
chamado pelo menos uma vez a cada 100ms para realizar a troca de processos. Devido ao pequeno 
intervalo de tempo entre as chamadas ao escalonador, sua execução deve ser bastante rápida, para que 
não se gaste muito tempo de UCP com trabalho de gerência. 
Mudança de contexto 
Para transferir o controle da UCP de um processo a outro, é necessário guardar o estado do processo 
em execução e carregar o estado do processo a entrar em execução. Esta tarefa é conhecida como mudança 
de contexto (ou troca de contexto). 
O tempo gasto na mudança de contexto varia, dependendo de fatores como velocidade da memória, 
quantidade de registradores e existência de instruções especiais. Este tempo costuma variar de 1 a 1000 
microssegundos. 
O contexto de um processo pode ser dividido em três elementos básicos: 
Contexto de hardware 
• O contexto de hardware constitui-se basicamente do conteúdo dos registradores. No 
momento em que o processo perde a UCP, o sistema salva suas informações. Ele é 
fundamental para a implementaçãodos sistemas multiprogramáveis. 
Sistemas Operacionais 
Marcio Quirino - 44 
 
Contexto de software 
• O contexto de software especifica características do processo que influenciarão na execução 
de um programa. Ele define basicamente três grupos de informações sobre um processo: 
identificação, quotas e privilégios. A identificação define o processo para o sistema de forma 
única, através de seu PID, UID e GID. Quotas são os limites de cada recurso que o sistema 
operacional pode alocar, como número de arquivos abertos, quantidade de memória, 
quantidade de subprocessos que podem ser criados etc. Privilégio é o que o processo pode 
ou não fazer em relação ao sistema e outros processos. 
Espaço de endereçamento 
• O espaço de endereçamento é a área de memória do processo em que o programa será 
executado e a área de memória onde os dados do processo serão armazenados. Cada 
processo possui seu próprio espaço de endereçamento, que deve ser protegido dos demais. 
Processos no Linux 
Os processos no Linux comportam-se como processos sequenciais tradicionais. É um sistema 
operacional multiusuário/multitarefa, que permite a execução simultânea de diversos processos, que podem 
pertencer a diferentes usuários. Mesmo que haja apenas um usuário logado no sistema, é comum a 
existência de diversos daemons em execução. 
Atenção 
Um exemplo é o daemon de impressão, responsável por fazer a alocação da impressora e controlar o envio de 
trabalhos de impressão. É uma parte importante do sistema, pois permite o compartilhamento da impressora por 
diversos processos, possivelmente pertencentes a diferentes usuários. 
A forma usual para criação de processos no Linux ocorre por meio da chamada de sistema fork(), 
conforme você já estudou neste tema. 
O processo filho recebe uma cópia exata do espaço de endereçamento do processo pai. Todos os 
valores de variáveis e demais objetos em memória serão idênticos, porém alterações realizadas por um dos 
processos em qualquer conteúdo de memória não afetarão o outro. 
Arquivos que foram abertos antes da chamada fork() permanecem abertos para o processo pai e 
para o processo filho. As alterações realizadas por qualquer um destes processos se tornam imediatamente 
disponíveis para o outro. Processos são identificados por um número inteiro conhecido como PID 
(identificação do processo). 
Algumas chamadas de sistema do Linux para o gerenciamento de processos são: 
Chamada de sistema Descrição 
fork() 
Cria um processo filho idêntico ao processo pai. Para o processo pai, retorna o PID do processo filho e, 
para o processo filho, retorna o valor 0. 
waitpid() Espera até que o processo filho passado como parâmetro termine sua execução. 
execve() 
Substitui a imagem de execução de um processo, fazendo com que, no lugar do processo corrente, seja 
executado o código do programa passado como parâmetro. 
exit() Termina a execução do processo e retorna como status o valor passado como parâmetro. 
 
Comandos do shell 
O shell, interpretador de comandos, é um programa que recebe comandos pelo teclado e providencia 
a execução desses comandos. 
Sistemas Operacionais 
Marcio Quirino - 45 
 
Comandos são ordens passadas ao sistema operacional para executar umadeterminada tarefa. 
Para colocar o shell em execução no Ubuntu, você deve abrir a lista de aplicativos clicando no botão 
que fica no canto inferior esquerdo de sua tela. Procure pelo aplicativo Terminal e clique sobre ele. Será 
aberta uma janela de texto com uma linha contendo o nome de seu usuário, o caractere @, o nome de seu 
sistema, e a sequência :~$. Essa linha é conhecida como prompt. 
Quando um usuário comum estiver utilizando o sistema, o shell apresenta, no final do prompt, o 
caractere $. Quando o shell estiver em uso pela conta root (administrador do sistema), o final do prompt será 
#. 
Para executar um comando, é necessário que ele tenha permissão de execução e que esteja no 
caminho de procura de arquivos (esteja no path). 
O path é o caminho de procura dos arquivos executáveis. Ele é armazenado na variável de ambiente 
PATH. Você pode ver o conteúdo desta variável com o comando: 
echo $PATH 
Um exemplo de retorno deste comando é: 
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/ 
usr/games:/usr/local/games:/snap/bin 
Por exemplo, o caminho “/usr/local/sbin:/usr/local/bin:/usr/sbin” significa que, ao ser digitado um 
comando, o interpretador de comandos iniciará a procura do comando no diretório “/usr/local/sbin”. Caso 
não encontre o arquivo nesse diretório, procurará em “/usr/local/bin”, depois em “/usr/sbin” e assim por 
diante. Caso o interpretador de comandos chegue até o último diretório do path e não encontre o arquivo 
digitado, será mostrada uma mensagem de erro. 
Ao digitar o nome de um programa ou comando e teclar Enter, o programa/comando será executado 
e receberá um número de identificação (PID – Process Identification). 
Todo o programa recebe também uma identificação de usuário (UID – User Identification) quando é 
executado, que determina quais serão suas permissões de acesso durante sua execução. O programa 
normalmente usa o UID do usuário que o executou, mas pode ser configurado pelo sistema para executar 
como um usuário específico. 
Comandos podem possuir uma ou mais opções. Entre o nome do comando e suas opções deve 
haver, pelo menos, um espaço em branco. As opções são usadas para controlar como o comando será 
executado. 
Comandos podem ser internos ou externos. Comandos internos são comandos que estão localizados 
dentro do interpretador de comandos (não ficam no disco). Eles são carregados na memória RAM do 
computador com o interpretador de comandos. 
Quando executa um comando, o interpretador de comandos primeiramente verifica se é um comando 
interno. Caso não seja, é verificado se é um comando externo. 
Comandos externos estão localizados no disco. Os comandos são procurados no disco de acordo 
com o PATH do sistema e são executados assim que encontrados. 
É possível consultar a lista de comandos já executados utilizando as setas para cima e para baixo 
do teclado. 
A tela pode ser rolada para frente e para trás ao pressionar a tecla Shift e clicando nas teclas Page 
Up e Page Down. 
Sistemas Operacionais 
Marcio Quirino - 46 
 
Programas podem executar em primeiro ou em segundo plano. Quando um programa está sendo 
executado em primeiro plano (foreground), é necessário esperar o término da execução do programa para 
executar outro. O prompt só é mostrado após o término da execução do programa. 
Quando um programa está sendo executado em segundo plano (background), não é necessário 
esperar o término de sua execução para executar um outro. Após iniciar um programa em background, é 
mostrado um número PID (identificação do processo) e o prompt é liberado, permitindo a execução de outro 
programa. 
Para iniciar um programa em primeiro plano, basta digitar seu nome normalmente. Para iniciar um 
programa em segundo plano, acrescente o caractere & ao final do comando. 
Teste a utilização do terminal: 
4. Execute o comando gedit. 
5. Tente utilizar o terminal enquanto a janela do gedit estiver aberta. 
6. Feche o gedit. 
7. Execute o comando “gedit &”. 
8. Tente utilizar o terminal enquanto a janela do gedit estiver aberta. 
9. Feche o gedit. 
Separando os comandos por “;” (ponto e vírgula), eles serão executados em sequência. Digite o 
comando “gedit; xcalc; xeyes” e tecle Enter. 
Comandos para controle de processos 
ps 
Mostra os processos em execução no sistema, a identificação do usuário que executou o processo, 
a hora em que o processo foi iniciado etc. 
Algumas opções: 
✓ a → Processos de todos os usuários. 
✓ x → Processos que não são controlados pelo terminal. 
✓ u -> Mostra o nome de usuário que iniciou o processo e a hora em que o processo foi iniciado. 
✓ m → Mostra a memória ocupada pelos processos. 
✓ f → Mostra a árvore de execuçãode processos. 
o Exemplo: ps -aux 
top 
Mostra continuamente informações sobre processos, utilização da UCP, uso da memória RAM, swap 
etc. 
Para encerrar a execução do top, deve ser pressionada a tecla q. 
Algumas teclas úteis: 
✓ espaço → Atualiza imediatamente a tela. 
✓ h → Mostra a tela de ajuda. 
✓ q -> Sai do programa. 
✓ k -> Finaliza um processo. Semelhante ao comando kill. Será necessário fornecer o número 
de identificação do processo (PID). 
<Ctrl> + <C> 
Encerra o processo que está sendo executado em primeiro plano. 
Sistemas Operacionais 
Marcio Quirino - 47 
 
<Ctrl> + <Z> 
Pausa a execução do processo que está em primeiro plano e mostra o número de seu job. 
O prompt do shell é liberado. 
O processo permanece na memória no ponto de processamento em que parou quando foi pausado. 
Sua execução pode ser retomada com os comandos fg ou bg. 
jobs 
Mostra os processos e seus respectivos números de job, que estão parados ou executando em 
segundo plano. 
bg 
Coloca um processo parado para executar em segundo plano. Para especificar o processo que 
entrará em execução em segundo plano, deve ser passado ao comando seu número obtido com o comando 
jobs. 
fg 
Coloca um processo parado ou executando em segundo plano para executar em primeiro plano. 
Para especificar o processo que irá para o primeiro plano, deve ser passado ao comando seu número obtido 
com o comando jobs. Caso não seja fornecido o número do job, ele irá para o primeiro plano o último 
processo pausado. 
kill 
Envia sinais a processos. Caso seja usado sem parâmetros, o kill enviará um sinal de término ao 
processo. 
Comando: kill [opções] [sinal] [número] 
Onde: 
✓ número → Número de identificação do processo obtido com o comando ps. 
✓ Também pode ser [%num], onde um é o número pelo comando jobs. 
✓ sinal → Sinal que será enviado ao processo. Se omitido, envia o sinal 15 (SIGTERM). 
Como opção pode ser passado ao comando a opção -9, que envia o sinal 9 (SIGKILL) ao processo. 
Trata-se um sinal de destruição que faz com que o processo seja terminado imediatamente. 
Somente o dono do processo ou o usuário root pode terminá-lo ou destruí-lo. 
killall 
Finaliza um ou mais processos e tem seu nome como base. 
killall5 
Envia sinal de finalização a todos os processos. 
nohup 
Executa o comando passado como parâmetro, ignorando os sinais de interrupção. 
Ainda pode ser finalizado com kill e <Ctrl>+<C>, mas sobrevive ao fechamento do terminal. 
pstree 
Mostra a árvore de processos do sistema. 
 
Sistemas Operacionais 
Marcio Quirino - 48 
 
Exemplos: 
1. Encerrando processos com kill. 
Abra um shell e coloque o gedit em execução com o comando: 
gedit & 
Execute o comando “ps -a” para listar os processos em execução e procure pela 
linha correspondente ao programa gedit. Um exemplo de saída do comando é: 
PID TTY TIME CMD 
1495 tty2 00:00:55 Xorg 
1522 tty2 00:00:00 gnome-session-b 
3379 pts/0 00:00:02 gedit 
3394 pts/0 00:00:00 ps 
Para o exemplo acima, percebemos que o gedit possui PID com valor 3379. O PID de seu 
processo deve ser outro. Verifique com atenção esse número. 
Para eliminar o processo 3379, utilize o comando: 
kill 3379 
Repare que o processo gedit foi fechado. 
2. Processos em primeiro plano e em segundo plano. 
Abra um shell e coloque o gedit em execução com o comando: 
xeyes 
Será colocado em execução o aplicativo xeyes, um par de olhos que acompanham a posição 
do cursor do mouse. 
Mexa o mouse pela tela e veja que o processo está funcionando normalmente. 
Em seguida, tente digitar algum comando no terminal. Você não conseguirá, pois o processo 
xeyes está executando em primeiro plano, impedindo o acesso ao terminal. 
Depois, pressione simultaneamente as teclas <Ctrl> e <Z>. Essa ação irá bloquear o 
processo xeyes e librar o prompt. A partir daí, você poderá entrar com novos comandos que 
o shell aceitará. 
Processos bloqueados não realizam processamento. Mexa novamente o mouse e verá que 
os olhos não acompanham o cursor. 
Para recolocar o processo em execução, você pode utilizar o comando fg (traz o processo 
para execução em primeiro plano) ou o comando bg (coloca o processo em execução em 
segundo plano). Vamos tentar com o bg. Para isso, execute o comando: 
bg 
Mexa o mouse e tente utilizar o comando. Você verá que ambos estão funcionando, pois, 
como o xeyes está executando em segundo plano, o terminal fica liberado. 
Vamos manter o xeyes em execução. 
Para colocar um processo em execução diretamente no segundo plano, você pode colocar 
o caractere & ao final do comando. Execute o comando: 
xcalc & 
A calculadora abrirá diretamente no segundo plano e teremos os três processos funcionando 
normalmente (shell, xeyes e calculadora). 
Sistemas Operacionais 
Marcio Quirino - 49 
 
Execute o comando: 
gedit 
Volte ao terminal e pressione <Ctrl>+<Z>. Com isso, o gedit será bloqueado e o shell 
liberado para execução. 
Execute o comando: 
jobs 
Será apresentada uma saída como: 
[1] Executando xeyes & 
[2]- Executando xcalc & 
[3]+ Parado gedit 
Pela saída, podemos ver que os processos xeyes e xcalc estão executando em segundo 
plano e que o processo gedit está bloqueado. Você pode colocar qualquer um deles 
executando em segundo plano com o comando fg, bastar colocar o número do job (que 
aparece entre colchetes) como parâmetro para o comando. 
Para colocar, por exemplo, o gedit executando em primeiro plano, execute o comando: 
fg 3 
2. Construção de programas concorrentes 
Compreender como ocorre a construção de programas concorrentes 
Subprocesso 
Quando um processo (processo pai) cria um outro processo, ele é conhecido como subprocesso ou 
processo filho. O subprocesso, por sua vez, pode criar outros subprocessos. 
A utilização de subprocessos permite dividir uma aplicação em partes que podem trabalhar de forma 
concorrente. Imagine, por exemplo: 
Exemplo 
Um servidor web que aceite requisições de clientes da internet e coloque as requisições em uma fila. Uma 
forma simples de implementar este servidor seria criar um processo que pegue a primeira requisição da fila, processe 
a requisição e devolva o resultado do processamento ao cliente que a solicitou. Após isso, ele pegaria a próxima 
requisição e faria o mesmo trabalho. 
O problema com essa solução é que ela não aproveita a capacidade de multiprocessamento dos 
sistemas atuais. Como existe apenas um processo em execução, somente um dos processadores do 
sistema é utilizado para atendimento das requisições. Além disso, se houver várias requisições complexas 
e demoradas e uma requisição simples, como uma pequena página HTML, entrar no final da fila, esta 
requisição mais simples, que poderia ser respondida rapidamente, será atendida somente depois que todas 
as demais forem processadas. 
A utilização de subprocessos resolve bem estes problemas. Se o servidor, no lugar de responder 
sequencialmente a cada requisição, criar um subprocesso para cada uma delas, tirará proveito da 
capacidade de multiprocessamento do sistema. Como cada requisição será tratada por um processo 
diferente, as requisições serão espalhadas pelos processadores do sistema, aproveitando sua capacidade 
de multiprocessamento. Além disso, como as requisições serão tratadas por diferentes processos, elas 
serão executadas concorrentemente. 
 
Sistemas Operacionais 
Marcio Quirino - 50 
 
Cada requisição será tratada por um processo diferente 
Um subprocesso é um processo completo. Então, cada subprocesso do servidor é, na realidade, um processo 
independente. 
Dessa forma, uma requisição simples, como a solicitação de uma página HTML, poderá ser iniciada 
e respondida rapidamente, ainda que existam outras requisições complexas solicitadas anteriormente e que 
elas ainda estejam sendo processadas. 
O trecho de código abaixo em Linguagem C exemplifica a parte de um servidor web simples que cria 
subprocessos para atendimento dasrequisições: 
while (1) { // Loop infinito 
req = pega_proxima_requisicao(); 
pid = fork(); 
if (pid == 0) { // Proceso filho 
processa_requisicao(req); 
exit(0); 
} 
} 
Entenda o significado de cada um deles: 
1. “pega_proxima_requisicao()” 
✓ Neste código, a rotina “pega_proxima_requisicao()” é responsável por verificar se existe 
alguma requisição enfileirada para atendimento. Se não houver, o processo pai fica 
bloqueado até que chegue uma nova requisição, sem impactar no desempenho do 
sistema. Enquanto isso, seus processos filhos continuam atendendo às requisições em 
andamento. 
2. “processa_requisicao()” 
✓ A rotina “processa_requisicao()” é executada somente pelo processo filho, uma vez que 
o comando if anterior faz essa verificação. Essa rotina fica encarregada do atendimento 
à requisição que foi enviada ao servidor web. Depois do processamento, a chamada de 
sistema “exit(0)” encerra o processo filho. 
3. “while (1) {…}” 
✓ Todo o código fica contido em um loop infinito “while (1) {…}”. Esse loop repetidamente 
pega a próxima requisição da fila, cria um processo filho para atendimento da requisição 
e retorna a aguardar uma nova requisição, enquanto o processo filho faz o 
processamento da requisição que acabou de chegar. 
O uso de subprocessos demanda consumo de diversos recursos do sistema. Sempre que um novo 
processo é criado, o sistema deve alocar recursos (contexto de hardware, contexto de software e espaço de 
endereçamento) para ele, além de consumir tempo de UCP. Além disso, cada processo possui seu próprio 
BCP. 
Threads 
Na tentativa de diminuir o tempo gasto na criação/eliminação de processos, bem como economizar 
recursos do sistema, foi introduzido o conceito de thread. Em um ambiente com múltiplos threads, não é 
necessário haver vários processos para implementar aplicações concorrentes. 
Threads compartilham o processador da mesma maneira que um processo. Cada thread possui seu 
próprio conjunto de registradores (contexto de hardware), porém compartilha o mesmo espaço de 
endereçamento com os demais threads do processo. No momento em que um thread perde a utilização do 
processador, o sistema salva suas informações. Threads passam pelos mesmos estados que um processo. 
A grande diferença entre subprocessos e threads é em relação ao espaço de endereçamento. 
Sistemas Operacionais 
Marcio Quirino - 51 
 
1. Subprocessos possuem, cada um, espaços independentes e protegidos. 
2. Threads, por outro lado, compartilham o mesmo espaço de endereçamento do processo, 
sem nenhuma proteção, permitindo que um thread possa alterar dados de outro thread. São 
desenvolvidos para trabalharem de forma cooperativa, voltados para desempenhar uma 
tarefa em conjunto, e são conhecidos como processos leves. 
A mudança de contexto entre threads em um mesmo processo exige uma alteração de um conjunto 
de registradores, mas não é necessário nenhum outro trabalho, como gerenciamento de memória, por 
exemplo, tornando-a mais leve que a mudança de contexto entre processos. 
 
Quando múltiplos threads estão presentes no mesmo processo, alguns campos da tabela de 
processos não ocorrem por processo, mas por thread. 
Em alguns sistemas, os threads são gerenciados no espaço do usuário, sem o conhecimento do 
sistema operacional. É o caso do pacote P-threads (POSIX). A comutação de threads é muito mais rápida 
quando é feita no espaço do usuário pelo fato de não precisar fazer uma chamada ao kernel. Porém, quando 
os threads são executados no espaço do usuário e um thread bloqueia, todo o processo é bloqueado pelo 
kernel. Threads no nível do usuário também fazem com que o tempo dedicado a threads de diferentes 
processos não seja distribuído de forma justa. 
Atenção 
Threads são muito úteis em sistemas com múltiplas UCP, nos quais o paralelismo real é possível. Elas 
permitem que ocorram múltiplas execuções no mesmo ambiente, fazendo com que várias partes de um mesmo 
processo estejam em execução concorrente em diferentes processadores. 
O termo multithread também é usado para descrever a permissão de múltiplos threads no mesmo 
processo. Algumas UCP oferecem suporte de hardware direto para multithread e permitem que 
chaveamentos de threads aconteçam em uma escala de tempo de nanossegundos. 
Processos com apenas um thread são conhecidos como monothread. 
Além de compartilhar o espaço de endereçamento, os threads podem compartilhar o mesmo conjunto 
de arquivos abertos, processos filhos, alarmes e sinais. 
Atenção 
É importante perceber que cada thread tem a sua própria pilha, que contém uma estrutura para cada rotina 
chamada, mas ainda não retornada. Essa estrutura contém as variáveis locais da rotina e o endereço de retorno para 
serem usados quando a chamada de rotina for encerrada. 
No Linux, os threads são criados com a chamada de sistema clone(). Sua sintaxe é: 
int clone(int (*fn)(void *), void *stack, int flags, void *arg) 
Sistemas Operacionais 
Marcio Quirino - 52 
 
Os flags mais comuns são: 
Flag 
Comportamento 
Quando utilizado Quando não utilizado 
CLONE_VM Cria um thread. Cria um processo. 
CLONE_FS 
Compartilha as informações sobre o sistema 
de arquivos. 
Não compartilha informações sobre o sistema de arquivos. 
CLONE_FILES Compartilha os descritores de arquivos. Copia os descritores de arquivos. 
CLONE_SIGHAND Compartilha a tabela do tratador de sinais. Copia a tabela do tratador de sinais. 
CLONE_PARENT 
O novo thread tem o mesmo pai que o 
chamador. 
O chamador é o pai do novo thread. 
SIGCHLD 
O thread envia o sinal SIGCHLD ao pai quando 
termina. 
O thread não envia o sinal SIGCHLD ao pai quando termina. 
 
Segue um exemplo de programa em Linguagem C que exemplifica a utilização de threads. Nele, são 
criados três threads dentro de um processo. O thread principal termina sua execução somente quando o 
último thread finaliza sua execução. 
#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sched.h> 
#include <sys/wait.h> 
 
#define TAMANHO_PILHA 65536 
#define _1SEGUNDO 1000000 
 
int global = 0; // Variável global alterada pelos threads 
 
static int funcaoThread(void *arg) { 
int id = *((int *) arg); // Identificação de cada thread 
int i; 
 
printf("Iniciou thread [%d]\n", id); 
for (i=0; i<3; i++) { // Loop no qual o thread altera a variável global 
printf("Thread [%d] incrementou \"global\" para %d.\n", id, ++global); 
usleep(_1SEGUNDO * (1+id/10.0)); 
 } 
printf("Saindo do thread [%d]\n", id); 
} 
 
int main () { 
void *pilha; 
int i, pid[3]; 
int id[3] = {1,2,3}; // Identificação a ser passada para cada thread 
 
for (i=0; i<3; i++) { // Alocando espaço para a pilha de cada thread 
if ((pilha = malloc(TAMANHO_PILHA)) == 0) { 
perror("Erro na alocação da pilha."); 
exit(1); 
} 
pid[i] = clone(funcaoThread, 
pilha + TAMANHO_PILHA, 
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, 
&(id[i])); // Criação de cada thread 
} 
printf("Thread principal aguardando demais threads terminarem.\n"); 
for (i=0; i < 3; i++) 
if (waitpid(pid[i], 0, 0) == -1) { // Aguarda até o término do thread 
perror("waitpid") 
exit(2); 
} 
Sistemas Operacionais 
Marcio Quirino - 53 
 
printf("Thread principal terminando.\n\n"); 
} 
Quando executado, o programa fornece a seguinte saída: 
Thread principal aguardando demais threads terminarem. 
Iniciou thread [3] 
Thread [3] incrementou "global" para 1. 
Iniciou thread [2] 
Thread [2] incrementou "global" para 2. 
Iniciou thread [1] 
Thread [1] incrementou "global" para 3. 
Thread [1] incrementou "global" para 4. 
Thread [2] incrementou "global" para 5. 
Thread [3] incrementou "global" para 6. 
Thread [1] incrementou "global" para 7. 
Thread [2] incrementou "global" para 8. 
Thread [3] incrementou "global" para 9. 
Saindo do thread [1] 
Saindo do thread [2] 
Saindo do thread [3] 
Thread principal terminando. 
Pela execução, vocêpode perceber que os valores das variáveis locais de cada thread não são 
influenciados pela execução dos demais threads. Porém, quando a variável “global” é modificada por um 
thread, esta alteração é vista imediatamente por todos os demais threads. 
Tipos de processos 
Existem basicamente dois tipos de processos relacionados ao tipo de processamento que executam. 
Nos cards, a seguir, entenda cada um deles: 
Os processos do tipo CPU-bound passam a maior parte do tempo no estado executando, realizando 
poucas operações de E/S. Costumam ser encontrados em aplicações científicas. 
Os processos do tipo I/O-bound passam a maior parte do tempo no estado bloqueado, por realizar 
elevado número de operações de E/S. Costumam ser encontrados em aplicações comerciais. Processos 
interativos também são exemplos deste tipo de processo. 
Processos e Threads No Linux 
O Linux pode duplicar um processo por meio da chamada de sistema fork(), mas também pode criar 
threads pela chamada de sistema clone(). No entanto, ele não faz distinção entre processos e threads. Toda 
entidade em execução, processo ou thread, será considerada como uma tarefa (task). Um processo com 
um único thread será considerado como uma tarefa, e um processo com n threads terá n estruturas de 
tarefas. 
Atenção 
As chamas de sistema fork() e clone() são bastante semelhantes. De fato, se clone() for invocada sem nenhum 
flag passado como parâmetro, seu comportamento será idêntico ao fork(). 
O contexto de uma tarefa do Linux não é mantido em uma única estrutura, mas são criadas várias 
estruturas independentes para cada contexto. Os dados de uma tarefa são acessados por meio de ponteiros 
que apontam para cada estrutura de cada contexto. Dessa forma, o compartilhamento de informações entre 
as tarefas fica facilitado, bastando que as tarefas apontem para as mesmas estruturas em memória. 
A fim de manter a compatibilidade com demais sistemas UNIX, o Linux associa um PID diferente a 
cada tarefa. Desta forma, diferentes threads de um processo terão diferentes PID. 
Quando um subprocesso é criado, a princípio, o Linux deveria alocar memória para os diferentes 
processos e copiar o conteúdo dos segmentos de memória do processo pai. Porém, copiar segmentos de 
Sistemas Operacionais 
Marcio Quirino - 54 
 
memória requer processamento e toma tempo. Então, para ser mais eficiente, o Linux simplesmente faz 
com que ambos (pai e filho) compartilhem o mesmo segmento de memória. 
Se os processos se limitarem à operação de consulta nos segmentos, não haverá problema, mas, 
se algum dos processos tentar escrever em um dos segmentos, neste momento, haverá a cópia do 
segmento compartilhado (mecanismo conhecido como cópia na escrita – copy on write). Além de aumentar 
o desempenho do sistema, esse mecanismo ajuda a diminuir o consumo de memória física. 
3. Comunicação entre processos 
Identificar o mecanismo de comunicação entre processos 
Processos de aplicações concorrentes 
O surgimento dos sistemas multiprogramáveis tornou possível criar aplicações nas quais diferentes 
partes do código de um programa pudessem executar de forma concorrente. Tais aplicações são conhecidas 
como aplicações concorrentes. 
É comum que processos de aplicações concorrentes compartilhem recursos do sistema. Não 
importam quais recursos são compartilhados, os problemas decorrentes serão os mesmos. O 
compartilhamento de recursos entre processos pode gerar situações indesejáveis capazes de comprometer 
o sistema. 
Se dois processos concorrentes trocam informações através de um buffer, um deles só poderá gravar 
dados caso o buffer não esteja cheio, enquanto um processo só poderá ler dados caso o buffer não esteja 
vazio. Em qualquer caso, os processos deverão aguardar até que o buffer esteja pronto para as operações 
de E/S. 
As considerações anteriores levam a três questões: 
1. Como um processo passa informações a outro? 
2. Como garantir que dois processos não se interfiram? 
3. Como realizar o sequenciamento quando um processo depende do outro? 
É bastante comum que aplicações concorrentes necessitem trocar informações. Tal comunicação 
pode se dar por meio de variáveis compartilhadas (memória compartilhada) ou por troca de mensagens. 
Porém, independentemente do mecanismo de comunicação utilizado, é preciso que os processos possam 
se manter sincronizados. 
Atenção 
Os mecanismos que garantem a comunicação entre processos concorrentes e o acesso a recursos 
compartilhados são chamados mecanismos de sincronização. Os mesmos mecanismos se aplicam a threads. 
Condição de corrida 
Em alguns sistemas, processos que estão trabalhando em conjunto, muitas vezes, utilizam uma 
memória comum, onde cada processo pode ler ou escrever. Este armazenamento compartilhado pode ser 
feito na memória principal ou em um arquivo em disco. 
Exemplo 
Imagine um programa que atualize o saldo de um cliente após o lançamento de um débito ou um crédito em 
um registro. 
O trecho do programa que faz a atualização poderia ser: 
Sistemas Operacionais 
Marcio Quirino - 55 
 
void atualiza_saldo(double valor, int conta) { 
Registro registro; 
registro = le_registro(conta); 
registro.saldo = registro.saldo + valor; 
grava_registro(registro, conta); 
} 
Exemplo 
Suponha que os funcionários Carlos e Orlando, caixas do banco, solicitem a atualização de uma conta cujo 
saldo é 500. Carlos faz uma operação de depósito de 100 e Orlando uma operação de saque de 200. Pode acontecer 
de o processo de Carlos ler o saldo da conta (500) e, ao mesmo tempo, o processo de Orlando ler o mesmo valor. 
Então, o processo de Carlos soma 100 e grava o registro com o valor 600. No entanto, o processo de Orlando já tem 
o valor de saldo de 500, subtrai 200 e fica com saldo de 300. Como o processo de Orlando grava o registro por último, 
o depósito não é computado, levando a uma inconsistência. O valor final das operações deveria ser 400, mas ficou 
registrado 300. 
Problemas como esses são conhecidos como condição de corrida, que ocorre quando dois ou mais 
processos estão acessando dados compartilhados e o resultado do processamento depende de quem 
executa e quando é executado. 
Região crítica 
Como evitar as condições de corrida? 
A forma mais simples é impedir que dois ou mais processos acessem um mesmo recurso no mesmo 
instante, impedindo que eles acessem o recurso compartilhado simultaneamente. Quando um processo 
estiver acessando o recurso, os demais deverão esperar. A esta exclusividade de acesso dá-se o nome de 
exclusão mútua, uma questão importante para o desenvolvimento de um sistema operacional. 
A parte do programa que acessa a memória compartilhada é denominada seção crítica ou região 
crítica (RC). Quando um processo é executado dentro de sua região crítica, nenhum outro processo pode 
entrar lá. 
{ 
...... 
Entra_Regiao_Critica(); 
Executa_Regiao_Critica(); 
Sai_Regiao_Critica(); 
...... 
} 
Não é suficiente evitar que o processo seja interrompido dentro da região crítica. São quatro as 
condições para uma boa solução: 
1. Não pode haver mais de um processo simultaneamente dentro de suas regiões críticas. 
2. Nenhuma suposição pode ser feita sobre a velocidade ou o número de UCP. 
3. Nenhum processo que execute fora de sua região crítica pode bloquear outro processo. 
4. Nenhum processo deve ter de esperar eternamente para entrar em sua região crítica 
(starvation). 
Para garantir a implementação da exclusão mútua, os processos envolvidos devem fazer acesso aos 
recursos compartilhados de forma sincronizada. 
Semáforos 
Um semáforo é uma variável inteira que conta sinais enviados a ela. Associadas aos semáforos, 
existem duas operações especiais: up e down. 
 
Sistemas Operacionais 
Marcio Quirino - 56 
 
Semáforos 
Semáforos e monitores são recursos para resolver o problema da condição de corrida. 
1. A operação down decrementa o valor do semáforo se ele for maior que 0, senãoo processo 
é bloqueado. 
2. A operação up incrementa o valor do semáforo caso não haja processos que tenham sido 
bloqueados pela operação down, senão um processo é desbloqueado. 
No caso da exclusão mútua, as instruções down e up funcionam como protocolos para que um 
processo possa entrar e sair de sua região crítica. O semáforo fica associado a um recurso compartilhado, 
indicando quando o recurso está sendo acessado por um dos processos concorrentes. Se seu valor for 
maior que 0, nenhum processo está utilizando o recurso. Caso contrário, o processo fica impedido de 
acessar o recurso. 
Sempre que deseja entrar na sua região crítica, um processo executa uma instrução down. Se o 
semáforo for maior que 0, ele é decrementado de 1, e o processo que solicitou a operação pode executar 
sua região crítica. Se uma instrução down é executada em um semáforo cujo valor seja 0, o processo que 
solicitou a operação ficará no estado bloqueado em uma fila associada ao semáforo. 
Quando o processo que está acessando o recurso sai de sua região crítica, ele executa uma 
instrução up, incrementando o semáforo de 1 e liberando o acesso ao recurso. Se um ou mais processos 
estiverem esperando, o sistema escolhe um processo na fila de espera e muda seu estado para pronto. 
As operações up e down são realizadas pelo sistema operacional, que deve garantir que elas sejam executadas 
atomicamente. 
A correção para o caso anterior de atualização do saldo de uma conta, com a utilização de semáforos, 
ficaria: 
void atualiza_saldo(double valor, int conta) { 
Registro registro; 
down(mutex); 
registro = le_registro(conta); 
registro.saldo = registro.saldo + valor; 
grava_registro(registro, conta); 
up(mutex); 
} 
Com a utilização de semáforos, somente um dos processos estará dentro da região crítica em 
determinado instante. Voltemos ao caso dos caixas Carlos e Orlando: 
Exemplo 
Ambos solicitaram a atualização de uma conta cujo saldo é 500. Com a utilização de semáforos, antes de o 
processo de Carlos ler o saldo, é realizada a operação down(mutex). Supondo que não haja outro processo na região 
crítica, o semáforo mutex permitirá a entrada do processo de Carlos. Quando o processo de Orlando tenta fazer sua 
operação, também se chamará down(mutex), mas, como o processo de Carlos está na região crítica, o processo de 
Orlando será bloqueado pelo semáforo. O processo de Carlos segue normalmente, faz o depósito de 100 e atualiza o 
saldo para 600. Ao sair da região crítica, o processo de Carlos faz up(mutex), liberando o processo de Orlando, que 
faz a leitura do saldo já atualizado (600). Assim, o processo faz o saque de 200 e atualiza o saldo para 400. Ao final, o 
processo de Orlando faz up(mutex), liberando novamente a região crítica. Vemos que, com a utilização de semáforos, 
não ocorre a inconsistência vista anteriormente. 
Para conhecer os programas em Linguagem C para Linux que fazem operações concorrentes de 
saque e depósito, consulte o documento Utilização de semáforo na solução de condição de corrida. 
Sistemas Operacionais 
Marcio Quirino - 57 
 
Utilização de semáforo na solução de condição de corrida 
A listagem do Anexo I mostra um programa com 2 threads que são executados concorrentemente. 
O thread “funcaoDeposito” realiza uma operação de depósito de 100 em uma conta, enquanto o thread 
“funcaoSaque” realiza um saque de 200 na mesma conta. 
A função responsável por atualizar o saldo é a “atualiza_saldo”. De modo a provocar a situação de 
haver dois threads dentro da região crítica, foi introduzida a chamada de sistema usleep(1000), que faz com 
que a função bloqueie por 1ms. Esse tempo será suficiente para provocar a ocorrência da condição de 
corrida no processo, em que os dois threads tentarão atualizar a mesma variável simultaneamente, fazendo 
com que o resultado seja inconsistente. 
Durante a execução, os dois threads solicitarão a atualização do saldo em “registro”. Como ambos 
leem a varável antes de alterá-la, somente uma das alterações terá efeito. 
O resultado do processamento do programa do Anexo I será: 
Saldo antes das operações = 500 
Iniciando operação [-200] 
Iniciando operação [100] 
Terminada operação [-200] 
Terminada operação [100] 
Saldo depois das operações = 600 
Você pode perceber que é iniciada a operação de saque de 200 e, antes que ela termine, é iniciada 
a operação de depósito de 100. O saldo antes das operações era 500 e o resultado do processamento 
deveria ser 400. Porém, devido à condição de corrida, o resultado do processamento foi 600. 
Para a solução deste problema, é necessária a definição de uma região crítica e sua proteção por 
semáforo, de modo que possa haver somente um processo em execução dentro da região crítica. 
Na listagem no Anexo II, você encontra o mesmo programa, com a inserção da região crítica 
protegida por um semáforo de nome mutex (linhas 43 a 50). O semáforo impede que dois threads executem 
concorrente dentro da região crítica, impedindo o acesso simultâneo ao saldo da conta. 
O resultado do processamento do programa do Anexo II será: 
Saldo antes das operações = 500 
Iniciando operação [-200] 
Terminada operação [-200] 
Iniciando operação [100] 
Terminada operação [100] 
Saldo depois das operações = 400 
Pela saída do processamento, é possível verificar que é iniciada a operação de saque de 200 e que 
a operação de depósito de 100 é iniciada somente após o término da operação de saque. Como o semáforo 
permite a execução de apenas um programa dentro da região crítica, não ocorre a condição de corrida. 
ANEXO I 
Programa sem semáforo, sujeito à condição de corrida. 
1 #define _GNU_SOURCE 
2 #include <stdio.h> 
3 #include <stdlib.h> 
4 #include <unistd.h> 
5 #include <sched.h> 
6 #include <sys/wait.h> 
7 
8 #define TAMANHO_PILHA 65536 
9 
10 typedef struct { 
11 double saldo; 
12 } Registro; 
13 
Sistemas Operacionais 
Marcio Quirino - 58 
 
14 Registro registro; 
15 
16 Registro le_registro(int conta){ 
17 return registro; 
18 } 
19 
20 void grava_registro(Registro reg, int conta){ 
21 registro = reg; 
22 } 
23 
24 void atualiza_saldo(double valor, int conta) { 
25 Registro registro; 
26 printf("Iniciando operação [%.2f]\n", valor); 
27 registro = le_registro(conta); 
28 usleep(1000); 
29 registro.saldo = registro.saldo + valor; 
30 grava_registro(registro, conta); 
31 printf("Terminada operação [%.2f]\n", valor); 
32 } 
33 
34 int funcaoDeposito(void *arg) { 
35 // Faz deposito de 100,00 
36 atualiza_saldo(100, 0); 
37 } 
38 
39 int funcaoSaque(void *arg) { 
40 // Faz saque de 200,00 
41 atualiza_saldo(-200, 0); 
42 } 
43 
44 int main() { 
45 void *pilha1, *pilha2; 
46 int pid1, pid2; 
47 
48 registro.saldo = 500; // Inicializa saldo 
49 printf("Saldo antes das operações = %.2f\n", registro.saldo); 
50 
51 // Aloca pilha para thread de depósito 
52 if ((pilha1 = malloc(TAMANHO_PILHA)) == 0) { 
53 perror("Erro na alocação da pilha."); 
54 exit(1); 
55 } 
56 // Inicia thread de depósito 
57 pid1 = clone(funcaoDeposito, 
58 pilha1 + TAMANHO_PILHA, 
59 CLONE_VM | SIGCHLD, 
60 NULL); 
61 
62 // Aloca pilha para thread de saque 
63 if ((pilha2 = malloc(TAMANHO_PILHA)) == 0) { 
64 perror("Erro na alocação da pilha."); 
65 exit(1); 
66 } 
67 // Inicia thread de saque 
68 pid2 = clone(funcaoSaque, 
69 pilha2 + TAMANHO_PILHA, 
70 CLONE_VM | SIGCHLD, 
71 NULL); 
72 
73 //Aguarda final da operações 
74 waitpid(pid1, 0, 0); 
75 waitpid(pid2, 0, 0); 
76 
77 printf("Saldo depois das operações = %.2f\n", registro.saldo); 
78 } 
ANEXO II 
Programa com semáforo, solucionando a condição de corrida. 
Sistemas Operacionais 
Marcio Quirino - 59 
 
1 /*********************************\ 
 2 * * 
 3 * COMPILAR COM PARÂMETRO -pthread * 
 4 * * 
 5 \*********************************/ 
 6 
 7 #define _GNU_SOURCE 
 8 #include <stdio.h> 
 9#include <stdlib.h> 
10 #include <unistd.h> 
11 #include <sched.h> 
12 #include <sys/wait.h> 
13 #include <semaphore.h> 
14 
15 #define TAMANHO_PILHA 65536 
16 
17 sem_t mutex; // Cria semáforo mutex 
18 
19 void up(sem_t *sem) { 
20 sem_wait(sem); 
21 } 
22 
23 void down(sem_t *sem) { 
24 sem_post(sem); 
25 } 
26 
27 typedef struct { 
28 double saldo; 
29 } Registro; 
30 
31 Registro registro; 
32 
33 Registro le_registro(int conta){ 
34 return registro; 
35 } 
36 
37 void grava_registro(Registro reg, int conta){ 
38 registro = reg; 
39 } 
40 
41 void atualiza_saldo(double valor, int conta) { 
42 Registro registro; 
43 up(&mutex); 
44 printf("Iniciando operação [%.2f]\n", valor); 
45 registro = le_registro(conta); 
46 usleep(1000); 
47 registro.saldo = registro.saldo + valor; 
48 grava_registro(registro, conta); 
49 printf("Terminada operação [%.2f]\n", valor); 
50 down(&mutex); 
51 } 
52 
53 int funcaoDeposito(void *arg) { 
54 // Faz deposito de 100,00 
55 atualiza_saldo(100, 0); 
56 } 
57 
58 int funcaoSaque(void *arg) { 
59 // Faz saque de 200,00 
60 atualiza_saldo(-200, 0); 
61 } 
62 
63 int main() { 
64 void *pilha1, *pilha2; 
65 int pid1, pid2; 
66 
67 // Inicializa mutex om valor 1 (somente um thread na região crítica) 
68 sem_init(&mutex, 1, 1); 
69 
Sistemas Operacionais 
Marcio Quirino - 60 
 
70 registro.saldo = 500; // Inicializa saldo 
71 printf("Saldo antes das operações = %.2f\n", registro.saldo); 
72 
73 // Aloca pilha para thread de depósito 
74 if ((pilha1 = malloc(TAMANHO_PILHA)) == 0) { 
75 perror("Erro na alocação da pilha."); 
76 exit(1); 
77 } 
78 // Inicia thread de depósito 
79 pid1 = clone(funcaoDeposito, 
80 pilha1 + TAMANHO_PILHA, 
81 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, 
82 NULL); 
83 
84 // Aloca pilha para thread de saque 
85 if ((pilha2 = malloc(TAMANHO_PILHA)) == 0) { 
86 perror("Erro na alocação da pilha."); 
87 exit(1); 
88 } 
89 // Inicia thread de saque 
90 pid2 = clone(funcaoSaque, 
91 pilha2 + TAMANHO_PILHA, 
92 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, 
93 NULL); 
94 
95 //Aguarda final da operações 
96 waitpid(pid1, 0, 0); 
97 waitpid(pid2, 0, 0); 
98 
99 printf("Saldo depois das operações = %.2f\n", registro.saldo); 
100 } 
Monitores 
O uso de semáforos exige do programador muito cuidado, pois qualquer engano pode levar a 
problemas de sincronização imprevisíveis e difíceis de reproduzir. Monitores são mecanismos de 
sincronização de alto nível que tentam tornar mais fáceis o desenvolvimento e a correção de programas 
concorrentes. 
Um monitor é uma coleção de variáveis, procedimentos e estruturas de dados que são agrupados 
em um pacote. Em determinado instante, somente um processo pode estar ativo em um monitor. Toda vez 
que algum processo chama um procedimento do monitor, ele verifica se já existe outro processo executando 
qualquer procedimento do monitor. Caso exista, o processo ficará aguardando a sua vez, até que tenha 
permissão para executar. 
 
Sistemas Operacionais 
Marcio Quirino - 61 
 
As variáveis globais do monitor são visíveis apenas a ele e a seus procedimentos. O bloco de 
comandos do monitor é responsável por inicializar essas variáveis, sendo executado apenas uma vez na 
ativação do programa onde está declarado o monitor. 
Cabe ao compilador implementar as exclusões mútuas em entradas de monitor. A cláusula 
synchronized da linguagem Java é um exemplo de implementação de monitores. O programador transforma 
regiões críticas em procedimentos de monitor, colocando todas as regiões críticas em forma de 
procedimentos no monitor. Assim, o desenvolvimento de programas concorrentes fica mais fácil. 
Sincronização no Linux 
O Linux oferece suporte à utilização de semáforos para sincronização de tarefas por meio da 
chamada de sistema sem_wait(), que realiza a operação up(), e da chamada de sistema sem_post(), que 
realiza a operação down(). 
Quando sem_wait() é invocada e o valor do semáforo é zero, a tarefa que faz a invocação é 
bloqueada até que o semáforo seja liberado por meio da função sem_post(). Porém, em algumas situações, 
a tarefa pode querer apenas verificar se é possível prosseguir, mas não é interessante bloquear, caso não 
possa prosseguir. 
Atenção 
Para esses casos, pode ser utilizada a chamada de sistema sem_trywait(), que tem funcionamento parecido 
com a sem_wait(), exceto pelo fato de que, se o decremento não puder ser executado imediatamente, a chamada de 
sistema retorna um erro sem bloqueio. 
Além da utilização de semáforos para sincronização de processos, o Linux permite a comunicação 
entre processos por meio de troca de mensagens e de sinais. 
A troca de mensagens pode ser implementada pelo mecanismo de pipe. O pipe ( | ) é um mecanismo 
especial de redirecionamento utilizado para conectar a saída padrão de um processo à entrada padrão de 
outro processo. Por exemplo, os comandos a seguir juntam todos os arquivos com extensão “.txt”, 
ordenando suas linhas e retirando as duplicadas. 
cat *.txt | sort | uniq 
Entenda o significado de cada um deles: 
1. O comando “cat *.txt” joga na saída padrão (tela) o conteúdo de todos os arquivos presentes 
no diretório e que possuem extensão “.txt”. 
2. O comando “sort” recebe linhas por sua entrada padrão (inicialmente, o teclado), ordena as 
linhas e envia as linhas devidamente ordenadas para a saída padrão. 
3. O comando “uniq” recebe linhas por sua entrada padrão e elimina as linhas duplicadas, 
enviando para a saída padrão somente as linhas que não estão em duplicidade. 
Quando é utilizada a barra vertical ( | ) entre os comandos, é introduzido um pipe entre as tarefas, ou 
seja, as tarefas são colocadas em execução concorrente, e a saída padrão da tarefa à esquerda do pipe é 
conectada à entrada padrão da tarefa à direita do pipe. Assim, no exemplo, a saída do comando “cat *.txt” 
é enviada para a entrada do comando “sort”, que faz a ordenação, e sua saída é enviada à entrada do 
comando “uniq”, que elimina as linhas repetidas e, finalmente, joga o resultado de seu processamento para 
a saída padrão (o monitor, por padrão). 
Outra forma de comunicação entre processos no Linux ocorre por meio de envio de sinais, que são 
enviados na ocorrência de eventos, como a chegada de uma informação pela rede, o fim de um 
temporizador, o término da execução de um processo filho etc. São eventos que chegam ao processo e 
Sistemas Operacionais 
Marcio Quirino - 62 
 
precisam ser tratados de alguma forma. Para isso, é necessário definir uma rotina para o tratamento do 
evento. 
São exemplos de sinais do Linux: 
Sinal Ação padrão Comentário 
SIGHUP Terminar Gerado pelo fim do terminal controlador. 
SIGTERM Terminar Informa que deve parar a execução. 
SIGINT Terminar Recebeu uma interrupção + pelo terminal controlador. 
SIGKILL Terminal Força a finalização do processo. 
SIGTSTP Suspender Processo deve ser suspenso (+). 
SIGSTOP Suspender Processo deve ser suspenso. Semelhante ao SIGTSTP, mas não pode ser sobrescrito. 
SIGCONT Retornar à execução se estiver suspenso. 
SIGCHLD Ignorar Informa ao processo pai que um processo filho terminou ou foi suspenso. 
SIGALRM Terminar Fim de temporizador. 
SIGURG Ignorar Condição urgente no socket. Normalmente, aviso de chegada de pacote de rede. 
SIGUSR1 Terminar Sinal definido pelo usuário. 
SIGUSR2 Terminar Sinal definido pelo usuário. 
Quando um sinal chega ao processo, ele pode: 
✓ Receber o tratamento padrão definido pelo kernel. 
✓ Ser capturado, sendo, então, tratado por uma função definida pelo usuário. 
✓ Ser ignorado. 
Para os sinais SIGKILL e SIGSTOP, sempre é executado o tratamento padrão. Eles não podem ser 
capturados nem ignorados. 
Sinais podem ser gerados por: 
✓ Exceções de hardware. 
✓ Condições de software. 
✓ Pelo shell com o comando kill.✓ Por outro processo, utilizando a chamada de sistema kill(). 
✓ Por uma combinação de teclas, como, por exemplo, < Ctrl> + < C>. 
✓ Controle de processos. 
As principais chamadas de sistema relativas ao tratamento de sinais são: 
Chamada de sistema Descrição 
signal() Instala rotina para tratamento do sinal. 
sigaction() Define a ação a ser tomada nos sinais. 
sigreturn() Retorna de um sinal. 
sigpending() Obtém o conjunto de sinais bloqueados. 
kill () Envia um sinal para um processo. 
alarm() Ajusta o alarme do relógio para envio de um sinal. 
pause() Suspende o chamador até o próximo sinal. 
Sistemas Operacionais 
Marcio Quirino - 63 
 
Tratamento de sinais em Linux 
No final deste documento, você encontrará um pequeno programa que exemplifica a utilização da 
chamada de sistema signal(), que faz a instalação de uma rotina para capturar sinais e modificar o 
comportamento padrão destes sinais. 
A ação padrão dos sinais SIGINT e SIGTERM é finalizar a execução do processo. Neste programa, 
vamos capturar esses sinais e executar nossa própria ação, evitando que o processo seja terminado quando 
receber os sinais A linha 7 define uma função de nome captura() que será utilizada como função para 
tratamento dos sinais. Ela verifica o tipo de sinal recebido e coloca essa informação na saída padrão. Antes 
de terminar, ela mostra a mensagem “Pretendo continuar executando!!!” e o processo continua executando 
normalmente. 
A linha 18 faz a instalação da função rotina para o tratamento dos sinais SIGINT e SIGTERM por 
intermédio da chamada de sistema signal(). A partir deste ponto, sempre que chegar qualquer um destes 
sinais, a execução do processo será desviada para a função captura(). 
Ao final, o processo entra em um loop infinito no qual, a cada segundo, ele emite uma mensagem 
afirmando que está executando normalmente. 
Ao ser colocado em execução, o processo começa a exibir uma série de mensagens informando que 
está vivo. 
Para testar o sinal SIGINT, utilizaremos o próprio terminal no qual o processo está executando. 
Ao pressionar simultaneamente as teclas <Ctrl>+<C>, o sinal SIGINT é enviado ao processo, que 
faz com que ele seja encerrado. Como nosso programa faz a captura deste sinal, no lugar de ser encerrado, 
a execução do processo será desviada para a rotina captura, que verifica o tipo do sinal, mostra essa 
informação e informa que continuará executando. 
O mesmo teste pode ser realizado para verificar a captura do sinal SIGTERM, mas, para enviar esse 
sinal, utilizaremos o comando kill. Esse comando é utilizado para enviar sinais a processos, informando 
como parâmetro o sinal que deve ser enviado. Se não for informado o tipo de sinal, por padrão é enviado o 
sinal SIGTERM. 
Primeiramente, precisamos descobrir o PID do processo que queremos terminar. Para isso, é 
necessário abrir outro terminal e executar o comando: 
ps -a 
Verificamos o número do processo (PID) e enviamos o sinal para ele. Se o PID for, por exemplo, 
8053, enviamos o sinal SIGTERM por intermédio do comando: 
kill 8053 
De forma semelhante ao explicado para o SIGINT, o sinal SIGTERM será capturado e uma 
mensagem será exibida na tela. 
Não importa o tipo de sinal enviado (SIGINT ou SIGTERM), o processo mostrará uma mensagem 
informando o sinal recebido e continuará executando e informando a cada segundo que está vivo. 
Uma forma de terminar a execução do processo é por intermédio do sinal SIGKILL, que não pode 
ser capturado. Para enviar o sinal SIGKILL, podemos utilizar o comando “kill -s SIGKILL <PID>” ou o 
comando “kill -9 <PID>”, onde <PID> será o PID do processo a ser encerrado. Para o exemplo anterior, 
podemos encerrar o processo por intermédio do comando: 
Kill -9 8053 
Sistemas Operacionais 
Marcio Quirino - 64 
 
 
Exemplo para tratamento de sinais 
1 #include <signal.h> 
2 #include <stdio.h> 
3 #include <stdlib.h> 
4 #include <unistd.h> 
5 
6 // Rotina para tratamento do sinal capturado 
7 static void captura(int sinal) { 
8 if (sinal == SIGINT) 
9 printf("Recebido o sinal SIGINT.\n"); 
10 if (sinal == SIGTERM) 
11 printf("Recebido o sinal SIGTERM.\n"); 
12 printf("Pretendo continuar executando!!!\n"); 
13 } 
14 
15 int main(){ 
16 int i; 
17 // Captura os sinais SIGINT e SIGTERM 
18 if ((signal(SIGINT, captura) == SIG_ERR) || (signal(SIGTERM, captura) == SIG_ERR)) { 
19 printf("Erro ao instalar o tratador do sinais.\n"); 
20 exit(1); 
21 } 
22 i = 1; 
23 while (1) { // Loop infinito 
24 printf("Estou vivo [%d].\n", i++); 
25 usleep(1000000); 
26 } 
27 } 
4. Formas de escalonamento 
Comparar as diferentes formas de escalonamento 
Escalonamento 
A multiprogramação tem como objetivo permitir que, a todo instante, haja algum processo para 
maximizar a utilização da UCP. 
O conceito que possibilitou a implementação de sistemas multiprogramáveis foi a possibilidade de a 
UCP ser compartilhada entre diversos processos. Portanto, deve existir um critério para determinar a ordem 
da escolha dos processos para execução dentre os vários que concorrem pela UCP. 
O procedimento de seleção é conhecido como escalonamento (scheduling). A parte do sistema 
operacional responsável pelo escalonamento é o escalonador (scheduler), às vezes chamado de agendador. 
Sempre que a UCP se torna ociosa, o escalonador seleciona um processo dentre aqueles que estão na 
memória prontos para serem executados (na fila de processos no estado pronto) e aloca a UCP para que 
ele possa ser executado. 
A principal função de um algoritmo de escalonamento é decidir qual dos processos prontos deve ser alocado 
à UCP. 
O algoritmo de escalonamento não é o único responsável pelo tempo de execução de um processo. 
Ele afeta somente o tempo de espera na fila de processos prontos, e pode ser classificado como preemptivo 
ou não preemptivo. Quando o sistema pode interromper um processo durante sua execução para colocá-lo 
no estado pronto e colocar outro processo no estado executando, tem-se um sistema preemptivo. Caso 
contrário, há um sistema não preemptivo. 
 
 
Sistemas Operacionais 
Marcio Quirino - 65 
 
Preemptivo 
O escalonamento preemptivo permite que o sistema dê atenção imediata a processos mais prioritários, além 
de proporcionar melhor tempo de resposta em sistemas de tempo compartilhado. Outro benefício decorrente é o 
compartilhamento do processador de maneira mais uniforme. 
Realizar o escalonamento preemptivo exige que uma interrupção de relógio ocorra ao fim do intervalo 
para devolver o controle da UCP ao escalonador. 
A troca de um processo por outro na UCP (mudança de contexto) causada pela preempção gera um 
overhead ao sistema. Para não se tornar crítico, o sistema deve estabelecer corretamente os critérios de 
preempção. 
Atenção 
Sistemas que usam escalonamento preemptivo têm o problema da condição de corrida, o que não ocorre com 
sistemas que usam escalonamento não preemptivo. No escalonamento não preemptivo, quando um processo ganha 
o direito de utilizar a UCP, nenhum outro processo pode tirar dele esse recurso. 
Clique nas barras para ver as informações. 
Escalonamento First In First Out (FIFO) 
Algoritmo de escalonamento também conhecido como primeiro a chegar, primeiro a ser servido (first 
come, first served). 
A grande força deste algoritmo é que ele é fácil de aprender e de programar. 
Nesse escalonamento, o processo que chegar primeiro é o primeiro a ser selecionado para execução. 
É preciso apenas uma fila, em que os processos que passam para o estado pronto entram no seu final. 
Quando um processo ganha a UCP, ele a utiliza sem ser interrompido, caracterizando-o como um algoritmo 
não preemptivo. 
O problema do escalonamento FIFO é a impossibilidade de se prever quando um processo terá sua 
execução iniciada. Outro problema é a possibilidade de processos CPU-bound de menor importância 
prejudicarem processos I/O-bound mais prioritários. 
Este algoritmofoi inicialmente implementado em sistemas batch. 
Sistema batch 
Tipo de processamento de dados em lote que não depende da interação com o usuário. 
Escalonamento Shortest Job First (SJF) 
O algoritmo SJF (tarefa mais curta primeiro) associa a cada processo seu tempo de execução. 
Quando a UCP está livre, o processo no estado pronto que precisar de menos tempo para terminar é 
selecionado para execução. 
O escalonamento SJF beneficia processos que necessitam de pouco processamento e reduzem o 
tempo médio de espera em relação ao FIFO. O problema é determinar quanto tempo de UCP cada processo 
necessita para terminar seu processamento. Em ambientes de produção, é possível estimar o tempo de 
execução, mas, em ambientes de desenvolvimento, é muito difícil. 
Imagine quatro tarefas A, B, C e D com tempos de execução de 14, 8, 6 e 4 minutos, respectivamente. 
Ao executá-las nessa ordem, o tempo de retorno para A é 14 minutos, para B, 22 minutos, para C, 28 minutos 
e, para D, 32 minutos, resultando em uma média de 24 minutos. Agora, considere executar essas quatro 
tarefas usando o algoritmo da tarefa mais curta primeiro. Os tempos de retorno são agora 4, 10, 18 e 32 
minutos, o que resulta em uma média de 16 minutos. 
Sistemas Operacionais 
Marcio Quirino - 66 
 
É um algoritmo de escalonamento não preemptivo e, assim como o FIFO, também foi utilizado nos 
primeiros sistemas operacionais com processamento batch. 
Escalonamento Shortest Remaining Time Next (SRTN) 
O SRTN (tempo restante mais curto em seguida) é uma versão preemptiva do SJF. Nele, o 
escalonador escolhe o processo cujo tempo de execução restante é o mais curto. Para o seu funcionamento, 
o tempo de execução precisa ser conhecido antecipadamente. 
Quando uma nova tarefa chega, seu tempo total é comparado ao tempo restante do processo atual. 
Se a nova tarefa precisar de menos tempo para terminar do que o processo atual, ela é suspensa, e a nova 
tarefa é iniciada. Esse esquema permite que novas tarefas curtas tenham um bom desempenho. 
Escalonamento Cooperativo 
O SJF e o FIFO não são algoritmos de escalonamento aplicáveis a sistemas de tempo compartilhado, 
onde um tempo de resposta razoável deve ser garantido a usuários interativos. 
No escalonamento cooperativo, quando um processo já está em execução por determinado tempo, 
ele voluntariamente libera a UCP, retornando para a fila de processos prontos. 
Sua principal característica está no fato de a liberação da UCP ser uma tarefa realizada 
exclusivamente pelo processo em execução, que a libera para um outro processo. Não existe nenhuma 
intervenção do sistema operacional na execução do processo. Isto pode ocasionar sérios problemas na 
medida em que um programa pode não liberar a UCP ou um programa mal escrito pode entrar em loop, 
monopolizando a UCP. 
É um algoritmo de escalonamento não preemptivo. 
Escalonamento Circular (Round Robin) 
Esse algoritmo é bem semelhante ao FIFO. Entretanto, quando um processo passa para o estado 
executando, existe um tempo limite (conhecido como time-slice ou quantum) para utilização da UCP de 
forma contínua. Quando esse tempo expira, o processo volta ao estado pronto, dando a vez a outro 
processo. 
A fila de processos no estado pronto é tratada como uma fila circular. O escalonamento é realizado 
alocando a UCP para cada processo da fila no intervalo de tempo determinado pelo quantum. 
Se o quantum for muito pequeno, gasta-se muito tempo de UCP com trabalho administrativo. Se o 
quantum for muito grande, a interatividade fica prejudicada, já que um processo que sai de execução pode 
demorar muito a voltar. Em geral, o quantum varia de 10 a 100ms. 
Através do escalonamento circular, nenhum processo poderá monopolizar a UCP, caracterizando-o 
como um algoritmo de escalonamento preemptivo. 
 
Um problema do escalonamento circular é que ele não oferece qualquer tratamento diferenciado a 
processos I/O-bound. Assim, processos CPU-bound terão a tendência de monopolizar a utilização da UCP, 
enquanto processos I/O-bound permanecem à espera. 
Sistemas Operacionais 
Marcio Quirino - 67 
 
Escalonamento por Prioridade 
O escalonamento circular consegue melhorar a distribuição do tempo de UCP em relação aos 
escalonamentos não preemptivos, porém ainda não consegue implementar um compartilhamento equitativo 
entre os diferentes tipos de processos. 
Para solucionar esse problema, os processos I/O-bound devem levar alguma vantagem no 
escalonamento, a fim de compensar o tempo excessivo gasto no estado bloqueado. Como alguns processos 
devem ser tratados de maneira diferente dos outros, é preciso associar a cada um deles uma prioridade de 
execução. Assim, processos de maior prioridade são escalonados preferencialmente. 
A preempção por prioridade é implementada mediante um relógio que interrompe o processador 
periodicamente, para que a rotina de escalonamento reavalie prioridades e, possivelmente, escalone outro 
processo, caracterizando-o como um algoritmo de escalonamento preemptivo. 
Todos os sistemas de tempo compartilhado implementam algum esquema de prioridade, que é uma 
característica do contexto de software de um processo, podendo ser estática ou dinâmica. 
Tem-se a prioridade estática quando a prioridade não é modificada durante a existência do processo. 
Apesar da simplicidade de implementação, a prioridade estática pode ocasionar tempos de resposta 
elevados. 
Na prioridade dinâmica, a prioridade do processo pode ser ajustada de acordo com o tipo de 
processamento realizado pelo processo ou pela carga do sistema. Quando o processo sai do estado 
bloqueado, recebe um acréscimo à sua prioridade. Dessa forma, os processos I/O-bound terão mais chance 
de ser escalonados e de compensar o tempo que passam no estado bloqueado. 
Para evitar que processos com maior prioridade sejam executados indefinidamente, a prioridade é 
diminuída com o passar do tempo. 
Outra forma de obter prioridade dinâmica é fazer com que o quantum do processo seja inversamente 
proporcional à fração do último quantum utilizado. 
Embora os sistemas de prioridade dinâmica sejam mais complexos e gerem um overhead maior, o 
tempo de resposta oferecido compensa. 
Escalonamento por Múltiplas Filas 
Como os processos de um sistema possuem diferentes características de processamento, é difícil 
que um único mecanismo de escalonamento seja adequado a todos. Uma boa política seria classificar os 
processos em função do tipo de processamento realizado e aplicar a cada grupo mecanismos de 
escalonamentos distintos. 
O escalonamento por múltiplas filas implementa diversas filas de processo no estado pronto, onde 
cada processo é associado exclusivamente a uma delas. Cada fila possui um mecanismo próprio de 
escalonamento em função das características do processo. Nesse esquema, os processos devem ser 
classificados, previamente, em função do tipo de processamento para poderem ser encaminhados à 
determinada fila. 
Cada fila possui uma prioridade associada, que estabelece quais são prioritárias em relação às 
outras. O sistema só pode escalonar processos de uma fila se todas as outras filas de prioridade maior 
estiverem vazias. 
Para exemplificar esse escalonamento, considere que os processos, em função de suas 
características, sejam divididos em três grupos: sistema, interativo e batch. Os processos do sistema devem 
ser colocados em uma fila de prioridade superior aos outros processos, implementando um algoritmo de 
escalonamento baseado em prioridades. Os processos de usuários interativos devem estar em uma fila de 
prioridade intermediária, implementando, por exemplo, o escalonamento circular. O mesmo mecanismo de 
Sistemas Operacionais 
Marcio Quirino - 68 
 
escalonamento pode ser utilizado na fila de processos batch, com a diferença de que esta fila deverá possuir 
uma prioridade mais baixa. 
Escalonamento em Sistemas de Tempo Real 
Um sistema de tempo real é aquele em queo tempo tem um papel essencial. Tipicamente, um ou 
mais dispositivos físicos externos ao computador geram estímulos. O computador tem de reagir em 
conformidade dentro de um montante de tempo fixo. Exemplos de sistemas de tempo real são equipamentos 
que estão monitorando pacientes em uma UTI, o piloto automático de um avião e o controle de robôs em 
uma fábrica automatizada. Em todos esses casos, ter a resposta certa tarde demais é, muitas vezes, tão 
ruim quanto não tê-la. 
Sistemas em tempo real geralmente são categorizados como tempo real crítico, significando que há 
prazos absolutos que devem ser cumpridos, e tempo real não crítico, significando que descumprir um prazo 
ocasional é indesejável, mas, mesmo assim, tolerável. Em ambos os casos, o comportamento em tempo 
real é conseguido com a divisão do programa em uma série de processos, cada um dos quais é previsível 
e conhecido antecipadamente. Esses processos geralmente têm vida curta e podem ser concluídos em curto 
espaço de tempo. Quando um evento externo é detectado, cabe ao escalonador programar os processos 
de maneira que todos os prazos sejam atendidos. 
Os eventos a que um sistema de tempo real talvez tenha de responder podem ser categorizados 
ainda como periódicos (significando que eles ocorrem em intervalos regulares) ou aperiódicos (significando 
que eles ocorrem de maneira imprevisível). Dependendo de quanto tempo cada evento exige para o 
processamento, tratar de todos talvez não seja possível. Se há m eventos periódicos e o evento i ocorre 
com o período Pi e exige Ci segundos de tempo da UCP para lidar com cada evento, a carga só pode ser 
tratada se: 
 
 Diz-se de um sistema de tempo real que atende a esse critério que ele é escalonável, o que significa 
que ele realmente pode ser implementado. Um processo que não atende a esse critério não pode ser 
escalonado, pois o montante total de tempo de UCP que os processos querem coletivamente é maior do 
que a UCP pode proporcionar. 
Algoritmos de escalonamento de tempo real podem ser estáticos ou dinâmicos. Algoritmos estáticos 
tomam suas decisões de escalonamento antes de o sistema começar a ser executado. Algoritmos dinâmicos 
tomam suas decisões no tempo de execução, após ela ter começado. O escalonamento estático funciona 
apenas quando há uma informação perfeita disponível antecipadamente sobre o trabalho a ser feito e sobre 
os prazos que precisam ser cumpridos. Algoritmos de escalonamento dinâmico não têm essas restrições. 
Escalonamento de Threads 
Quando vários processos têm, cada um, múltiplos threads, há dois níveis de paralelismo presentes: 
processos e threads. O escalonamento nesses sistemas vai diferir, ainda, se são threads de usuário ou 
threads de núcleo. 
Sendo threads de usuário, o núcleo não tem ciência da existência dos threads. Assim, ele opera 
como sempre fez, escolhendo um processo A e dando a A o controle de seu quantum. O escalonador de 
thread dentro de A decide qual thread executar (A1, por exemplo). Dado que não há interrupções para 
multiprogramar threads, esse thread pode continuar a ser executado por quanto tempo quiser. Se ele utilizar 
todo o quantum do processo, o núcleo selecionará outro processo para executar. 
Quando o processo A executar novamente, o thread A1 retomará a execução. Ele continuará a 
consumir todo o tempo de A até que termine. No entanto, seu comportamento não afetará outros processos. 
Sistemas Operacionais 
Marcio Quirino - 69 
 
Eles receberão o que quer que o escalonador considere sua fração apropriada, não importa o que estiver 
acontecendo dentro do processo A. 
Agora, considere o caso em que os threads de A tenham relativamente pouco trabalho para fazer, 
por exemplo, 5ms de trabalho dentro de um quantum de 50ms. Em consequência, cada um é executado por 
um tempo. Então, cede a UCP de volta ao escalonador de threads. Isso pode levar à sequência A1, A2, A3, 
A1, A2, A3, A1, A2, A3, A1, antes que o núcleo chaveie para o processo B. 
O algoritmo de escalonamento usado pelo sistema de tempo de execução pode ser qualquer um dos 
descritos anteriormente. A única restrição é a ausência de um relógio para interromper um thread que esteja 
sendo executado há tempo demais. Como os threads cooperam, isso normalmente não é um problema. 
Vejamos agora a situação com threads de núcleo. Aqui, o núcleo escolhe um thread em particular 
para executar. Ele não precisa levar em conta a qual processo o thread pertence, mas pode fazer isso. O 
thread recebe um quantum e é suspenso compulsoriamente se o exceder. Com um quantum de 50ms e 
threads que são bloqueados após 5ms, a ordem do thread por algum período de 30ms pode ser A1, B1, A2, 
B2, A3, B3, algo que não é possível com esses parâmetros e threads de usuário. 
Uma diferença importante entre threads de usuário e de núcleo é o desempenho. Realizar um 
chaveamento de thread com threads de usuário exige um punhado de instruções de máquina. Com threads 
de núcleo, é necessário um chaveamento de contexto completo, mudar o mapa de memória e invalidar o 
cache, o que representa uma demora bem maior. Por outro lado, com threads de núcleo, ter um bloqueio de 
thread na E/S não suspende todo o processo, como ocorre com threads de usuário. 
Como o núcleo sabe que chavear de um thread no processo A para um thread no processo B é mais 
caro do que executar um segundo thread no processo A, ele pode levar essa informação em conta quando 
toma uma decisão. 
Outro fator importante é que os threads de usuário podem empregar um escalonador de thread 
específico de uma aplicação. 
Escalonamento no Linux 
O Linux suporta a multitarefa preemptiva, em que o escalonador decide que processo deve ser 
executado e quando executá-lo. Tomar essas decisões de modo que mantenha o equilíbrio entre justiça e 
desempenho para muitas cargas de trabalho diferentes é um dos desafios mais complicados dos sistemas 
operacionais modernos. 
O Linux é baseado em tarefas do núcleo. São definidas três classes de tarefas: 
1. FIFO em tempo real 
2. Escalonamento circular em tempo real 
3. Tempo compartilhado 
Entre essas três classes, é utilizado um escalonamento por múltiplas filas, em que a classe FIFO em 
tempo real é a fila de maior prioridade e a classe tempo compartilhado é a classe de menor prioridade. 
As tarefas FIFO em tempo real são escalonadas exclusivamente por prioridade, sem preempção. 
Sempre que houver uma tarefa FIFO em tempo real, ela utilizará o processador sem ser interrompida, a não 
ser que outra tarefa FIFO em tempo real de maior prioridade entre no estado pronto. 
O escalonamento circular em tempo real funciona com algoritmo de escalonamento circular (Round 
Robin), com um quantum associado a cada tarefa. Sempre que uma tarefa excede seu quantum, ocorre 
uma preempção, e a tarefa é colocada no final da fila de processos prontos. 
 
Sistemas Operacionais 
Marcio Quirino - 70 
 
Atenção 
Apesar do nome “tempo real”, nenhuma dessas classes é realmente de tempo real, pois o sistema não tem 
como garantir os limites de tempo necessários ao funcionamento de um sistema de tempo real. 
As tarefas de tempo real recebem prioridade de 0 a 99, sendo 0 o nível de prioridade mais alto e 99 
o nível de prioridade mais baixo. 
As tarefas de tempo compartilhado não competem com as tarefas de tempo real. Elas são 
escalonadas somente se não houver nenhuma tarefa de tempo real no estado pronto. As tarefas de tempo 
compartilhado recebem prioridade de 100 a 139, sendo 100 a prioridade mais alta e 139 a prioridade mais 
baixa desta fila. Dessa forma, o Linux possui um total de 140 níveis de prioridade. 
Existe um utilitário de linha de comando chamado nice, que pode ser utilizado para alterar a 
prioridade de uma tarefa. O nice recebe como parâmetro um valor (de -20 a +19), que é somado à prioridade 
do thread. Apenas a conta root (administrator do Linux) pode fornecer um valor negativo como parâmetro 
do nice. Issosignifica que um usuário comum pode solicitar apenas diminuição na prioridade de suas tarefas, 
nunca aumento de prioridade. 
Considerações finais 
Iniciamos nosso estudo aprendendo sobre o modelo de processo, fundamental para implementação 
de sistemas de tempo compartilhado, em que o usuário do sistema pode executar, concorrentemente, vários 
programas, tendo a ilusão de que estão todos executando em paralelo. 
Vimos ainda como a implementação de subprocessos e threads podem ser utilizados para o 
desenvolvimento de aplicações que façam uso da capacidade de multiprocessamento dos sistemas atuais. 
Tal técnica é de suma importância para o desenvolvimento de sistemas de alto desempenho. 
Na parte de comunicação e sincronização entre processos, você pode perceber que, apesar do 
desempenho que pode ser obtido com a programação concorrente, cuidados devem ser tomados, 
principalmente no tocante à atualização de dados compartilhados. Para isso, podemos utilizar técnicas 
oferecidas pelo sistema operacional, como semáforos, que definem e controlam o acesso a regiões críticas, 
evitando as condições de corrida. 
Por fim, estudamos os principais algoritmos de escalonamento que podem ser implementados pelos 
sistemas operacionais, vendo as principais caraterísticas de cada um deles. Como exemplo de algoritmos 
de escalonamento, vimos também como o Linux faz para selecionar o próximo processo a ser colocado em 
execução. 
Concluímos que o conhecimento acerca da gerência do processador de um sistema operacional e 
de como se comportam processos, subprocessos e threads eleva o nível de conhecimento de um 
desenvolvedor/programador, permitindo que ele se torne apto ao desenvolvimento de sistemas melhores e 
de maior desempenho. 
Referências 
DEITEL, H. M. Sistemas Operacionais. 3. ed. São Paulo: Pearson Prentice Hall, 2005. 
MACHADO, F. B.; MAIA, L. P. Arquitetura de Sistemas Operacionais. 5. ed. Rio de Janeiro: LTC, 
2013. 
NEMETH, E. et al. Manual completo do Linux: Guia do Administrador. 2. ed. São Paulo: Pearson 
Prentice Hall, 2007 
UBUNTU. Official Ubuntu Documentation. Consultado em meio eletrônico em: 2 ago. 2020. 
SILBERSCHATZ, A. Fundamentos de Sistemas Operacionais. 9. ed. Rio de Janeiro: LTC, 2013. 
Sistemas Operacionais 
Marcio Quirino - 71 
 
SILBERSCHATZ, A.; GALVIN, P. B. Sistemas Operacionais – Conceitos. 5. ed. São Paulo: Prentice 
Hall, 2000. 
SILVA, G. M. Guia Foca GNU/Linux. Consultado em meio eletrônico em: 2 ago. 2020. 
SOARES, L. F. G. Redes de Computadores – Das LANs, MANs e WANS às Redes ATM. 2. ed. Rio 
de Janeiro: Campus, 1995. 
TANENBAUM, A. S.; BOS, H. Sistemas Operacionais Modernos. 4. ed. São Paulo: Pearson 
Educacional do Brasil, 2016. 
TANENBAUM, A. S.; WOODHULL, A. S. Sistemas Operacionais – Projeto e Implementação. 3. ed. 
Porto Alegre: Bookman, 2008. 
TANENBAUM, A. S. Redes de Computadores. 5. ed. São Paulo: Pearson, 2011. 
TANENBAUM, A. S. Structured Computer Organization. 3. ed. Londres: Prentice Hall International, 
1990. 
Explore+ 
Um contratempo que pode ocorrer com a criação de problemas concorrentes é o impasse entre 
processos. Aprenda sobre este assunto lendo o capítulo 6 do livro Sistemas operacionais modernos, de 
Andrew Stuart Tanenbaum e Herbert Bos. 
 
Sistemas Operacionais 
Marcio Quirino - 72 
 
Memória 
Descrição 
Organização de funcionamento da memória de um computador: gerência pelo sistema operacional 
(SO), utilização da memória virtual e como ela é implementada no Linux. 
Propósito 
Apresentar as técnicas de gerência de memória empregadas pelos sistemas operacionais. 
Introdução 
Segundo von Neumann, para que um programa possa ser executado, suas instruções e seus dados 
devem estar alocados na memória principal, a fim de que possam ser referenciados diretamente. Disso 
decorre o fato de os processos ativos terem de estar alocados na memória para que possam executá-los. 
A necessidade de gerenciar os espaços disponíveis na memória, bem como o local onde estão as 
instruções e os dados de um processo, são, portanto, fundamentais para a sua execução. 
Mesmo nos antigos sistemas monotarefa isso já era necessário, sendo ainda mais importante nos 
modernos sistemas multitarefas. 
Além disso, o alto custo da memória e a sua exiguidade diante das necessidades dos programas 
tornaram ainda mais fundamental o gerenciamento eficiente desse recurso pelos sistemas operacionais 
(SO). 
Paginação, segmentação e memória virtual são técnicas comumente usadas nos SO modernos para 
aumentar a eficiência do gerenciamento. Como fazer esse gerenciamento e como funcionam as diversas 
técnicas são o objeto deste tema. 
1. Como os processos enxergam a memória e como ela é 
gerenciada 
Gerência de memória 
A memória do computador é um recurso extremamente importante e que exige um gerenciamento 
apurado. Ela é composta por vários elementos, tais como: registradores e cache (armazenamento interno); 
memória principal RAM (armazenamento primário) e armazenamento secundário; discos de estado sólido, 
magnéticos e óticos; e fitas magnéticas. 
Sistemas Operacionais 
Marcio Quirino - 73 
 
 
Figura 1: Elementos da memória. Fonte: SILBERSCHATZ, 2015. 
Um sistema de computação utiliza vários níveis de armazenamento, cada um com suas próprias 
características de custo, velocidade de acesso e capacidade. Como se pode notar na Figura 1, quanto mais 
rápida a memória (ou seja, mais próximo ao topo da figura), mais cara ela será e menor quantidade existirá 
no computador. 
Na Figura 1 também podemos verificar os três grandes tipos de armazenamento: 
Volátil 
Guarda as informações temporariamente, e requer corrente elétrica para reter dados. Quando a energia é 
desligada, todos os dados são apagados. 
A. Armazenamento Interno 
É constituído pela memória interna do processador e engloba os registradores e o cache. É a 
memória de trabalho efetiva do processador. Trata-se de uma memória volátil. 
B. Armazenamento Primário 
É constituído pela memória principal do computador, normalmente referenciada como memória 
RAM. Armazena o código dos programas e seus dados. Pode ser acessada diretamente pelo 
processador, que solicita a transferência de seu conteúdo para os registradores da CPU durante 
o processamento. É uma memória volátil. 
C. Armazenamento Secundário 
Também chamado de Armazenamento de Massa, é a memória que armazena os dados para uso 
posterior, já que é não volátil. Para que seu conteúdo possa ser manipulado, é necessário que 
seja transferido antes para a memória primária por meio de uma operação de leitura. 
O sistema operacional é o responsável por realizar a gerência da memória. Entre suas funções estão: 
• Alocar e desalocar os processos na memória. 
• Controlar os espaços disponíveis. 
• Impedir que um processo acesse o conteúdo da memória de outro processo. 
Sistemas Operacionais 
Marcio Quirino - 74 
 
• Transferir dados entre o armazenamento primário e secundário e vice-versa. 
Como os processos enxergam a memória 
Como já sabemos, a memória de um computador é composta por um conjunto de circuitos eletrônicos 
que são capazes de armazenar bits. Podemos considerar então que, do ponto vista do hardware, ela é um 
conjunto de bytes, que podem, por meio de um circuito eletrônico, ser acessados individualmente. Essa 
memória é denominada memória física, onde efetivamente os dados serão armazenados, e corresponde a 
um espaço de endereçamento físico, normalmente representado em hexadecimal. 
Do ponto de vista processual, entretanto, ela é vista como um conjunto de endereços lógicos que 
podem ser acessados diretamente por comandos da linguagem de máquina do processador. Essa memória 
lógica corresponde ao espaço de endereçamento do processo e, normalmente, nos sistemas atuais, é 
muitas vezes maior que a memória física disponível na máquina, gerando a chamada memória virtual. 
Dessa forma, podemos notar que os processos não enxergam a memóriafísica, mas apenas a 
memória lógica. Portanto, todas as referências a endereço para o processo correspondem ao seu espaço 
de endereçamento lógico, que lhe foi atribuído durante o processo de sua carga e que é independente do 
espaço de endereçamento de qualquer outro processo. 
O modelo de memória de um processo pode ser visto na Figura 2, onde temos: 
Text Área da memória que armazena o código do programa. 
Data Área de memória onde residem as variáveis do programa. 
Heap Área de trabalho do programa onde são alocadas variáveis temporárias e variáveis dinâmicas. 
Pilha Área onde ficam os registros de ativação de procedimentos, variáveis locais etc. 
 
 
Figura 2: Espaço de endereçamento de um processo. Fonte: EnsineMe. 
Dentro do espaço de endereçamento do programa, entre o Heap e a Pilha, temos uma área livre que 
permite que eles cresçam um em direção ao outro. 
Como o processo enxerga apenas os seus endereços lógicos e o circuito eletrônico enxerga somente 
os endereços físicos, é necessário, então, que se faça a tradução do endereço lógico para o físico, pois, 
dessa forma, um programa que referencia os seus endereços lógicos pode apontar para os respectivos 
endereços físicos. 
Sistemas Operacionais 
Marcio Quirino - 75 
 
O componente responsável por este mapeamento é o MMU (Memory Management Unit) que consiste 
em um conjunto de chips que realiza seu trabalho a partir das seguintes regras: 
A. Regra 1 
Se o endereço lógico é maior que o limite inferior e menor que o limite superior, o endereço é 
valido. Nesse caso, o endereço lógico é igual ao endereço físico. 
B. Regra 2 
Se o endereço lógico é menor que o limite superior, adiciona o endereço base ao endereço lógico 
e realiza o acesso no endereço resultante. Nesse caso, o endereço lógico é diferente do endereço 
físico. 
C. Regra 3 
Se o endereço lógico for maior que o limite superior ou menor que o limite inferior, o endereço é 
inválido e é gerada uma exceção. 
Os conceitos de limite superior e inferior serão tratados a seguir. 
Para um processo, a memória é exclusiva para as suas demandas, no entanto, a memória é sempre 
dividida entre outros processos. Mesmo quando o sistema é monotarefa, a memória terá uma área dedicada 
para o sistema operacional (Figura 3a). Enquanto nos sistemas multiprogramados, a utilização e 
concorrência da memória ocorre inclusive entre outros programas (Figura 3b). 
 
Figura 3: Processos compartilhando memória. Fonte: EnsineMe. 
Se não tivermos cuidado, um processo poderá “invadir” a área de outro, lendo e sobrescrevendo 
dados, o que acabaria por gerar erros. Como impedir que isso aconteça? 
Proteção de memória 
Para realizar a proteção de forma eficiente, temos que nos certificar que cada processo tenha um 
espaço de memória separado. Isso é fundamental para que possamos carregar vários processos na 
memória ao mesmo tempo, permitindo a execução concorrente deles, além de protegê-los uns dos outros. 
Sistemas Operacionais 
Marcio Quirino - 76 
 
A ideia básica da separação é que seja determinado um intervalo de endereços legais que possam 
ser acessados pelo processo, de forma a assegurar que esse acesso seja realizado exclusivamente por ele. 
É possível fornecer essa proteção usando dois registradores, geralmente um registrador base e um 
registrador limite, como ilustrado na Figura 4. 
 
Figura 4: Registradores base e limite. Fonte: SILBERSCHATZ, 2015. 
Quando um processo é alocado na memória, ele recebe um endereço inicial de carregamento 
(endereço base) e outro que corresponde ao tamanho total da área alocada ao processo (endereço limite). 
Ambos são armazenados, respectivamente, nos registradores base e limite. 
O registrador base estabelece o limite inferior da área do processo (300040), e a soma do limite com 
o endereço base define o limite superior da área do processo (420940), conforme o exemplo da Figura 4. 
A proteção do espaço da memória é assegurada pela MMU, que, ao receber um endereço da CPU 
de um programa rodando em modo usuário, verifica se ele se encontra no intervalo legal do processo. Se 
estiver, permite o acesso; caso contrário, gera um erro fatal, conforme ilustrado na Figura 5. 
 
Figura 5: Proteção de memória com base e limite. Fonte: SILBERSCHATZ, 2015. 
Sistemas Operacionais 
Marcio Quirino - 77 
 
Esse esquema impede que um programa rodando em modo usuário, de forma deliberada ou 
acidental, modifique o código ou as estruturas de dados do sistema operacional ou de outros processos de 
usuários. 
O carregamento dos registradores base e limite exige a execução de uma instrução privilegiada pelo 
Sistema Operacional (SO), concedida pelo SO estar em modo Kernel. Sendo assim, não é possível modificá-
lo sem este acesso privilegiado. 
Por sua vez, o sistema operacional, em modo kernel, pode acessar qualquer endereço de memória, 
sendo seu ou de qualquer outro processo de usuário. 
Assim, permite a carga de programas do usuário, a descarga destes em caso de erros, o acesso e a 
alteração de argumentos de chamadas de sistema, a execução de operações de entrada e saída a partir da 
memória principal e vários outros serviços. Em um sistema multiprocessado, por exemplo, é possível 
executar mudanças de contexto, transferindo o estado de um processo dos registradores para a memória 
principal, antes de carregar o contexto do próximo processo da memória principal para os registradores. 
Atenção 
O esquema de proteção aqui descrito é básico e, dependendo da política de alocação adotada, poderá sofrer 
modificações conforme veremos no próximo módulo. 
De acordo com o que foi visto, quando um processo é alocado na memória, ele recebe um endereço 
inicial para sua área de memória que é carregado no registrador base. Entretanto, o processo pode ser 
carregado inicialmente em uma posição e, depois de um tempo, pode ser desalocado, apenas para, em 
seguida, ser alocado novamente em outro endereço de memória. Para resolver essa situação temos o que 
chamamos de relocação. 
Pode parecer estranho o fato de um processo ser alocado, desalocado e depois ser realocado em 
outro ponto da memória. Contudo, dependendo da política de alocação, isso é possível, conforme veremos 
no próximo módulo. 
Relocação 
Um processo, quando alocado na memória principal, faz referências às suas posições, ou seja, aos 
endereços físicos dessa memória. Por essa razão, quando um módulo foi link-editado e seus endereços já 
estão associados às posições físicas do espaço de memória onde ele será alocado, diz-se que esse módulo 
está em Imagem de Memória, ou que ele está com Endereçamento Absoluto. 
Para que um processo possa ser alocado em qualquer posição da memória, ele não pode estar com 
endereçamento absoluto e, nesse caso, um mapeamento de endereços deverá ser feito entre os endereços 
dos objetos referenciados pelo processo (lógicos) e os endereços absolutos (físicos) no espaço ocupado 
por eles na memória principal. 
Chamamos de Espaço de Endereçamento o conjunto de endereços, sejam eles de dados ou de 
instruções, referenciados por um processo, podendo este ser: 
A. Espaço Lógico de Endereçamento 
O conjunto de objetos ou endereços lógicos referenciados. 
B. Espaço Físico de Endereçamento 
O conjunto de endereços físicos correspondentes. 
A relocação de memória é, portanto, a função que mapeia os endereços lógicos em endereços 
físicos. Ela pode ser realizada pelo link-editor durante a resolução das referências em aberto, na geração 
do módulo de carga. Os endereços são resolvidos em relação a uma base inicial e o processo só poderá 
ser alocado a partir dessa base, ou seja, sempre rodará no mesmo lugar da memória. 
Sistemas Operacionais 
Marcio Quirino - 78 
 
Alguns sistemas deixam essa tarefa de relocação para o carregador (loader) ou ligador-carregador 
(link-loader), que faz a resolução das referências externas e a relocação de endereços no instante de 
carregar o processo na memóriapara sua execução. 
No primeiro caso (link-editor), a carga em imagem de memória sempre roda no mesmo lugar da 
memória, enquanto no segundo caso ela pode rodar em qualquer lugar. 
Quando esse mapeamento de endereços é feito antes do carregamento do módulo, o processo é 
denominado Relocação Estática. 
Para que a tradução dinâmica de endereços possa ser efetuada, é preciso que toda referência seja 
lógica, isto é, nenhum endereço no programa poderá estar representando uma posição física, pois será 
mapeado pelo hardware. Esse outro processo é chamado de Relocação Dinâmica. 
Para a relocação, o nosso registrador base será agora chamado de registrador de relocação e ele 
receberá o endereço inicial da área de memória do processo. 
Observe a Figura 6: 
 
Figura 6: Relocação dinâmica. Fonte: SILBERSCHATZ, 2015. 
É possível notar que o valor do registrador de relocação é 14000, portanto, ao receber o endereço 
lógico 346, ele soma 14000 e acessa o endereço 14346. 
Atenção 
Como veremos adiante, existem técnicas de gerência de memória que retiram o processo que está bloqueado 
da memória e, quando ele for executado novamente, recarregam-no em outro endereço. Isso só é possível devido à 
relocação. 
E como fica a proteção de memória nesse caso? Como a base agora é o registrador de relocação, 
isso significa que não existirá endereço menor que este, portanto, a proteção deve ser realizada apenas 
para verificar se o endereço lógico não é maior que o valor do registrador limite, pois, assim, o programa 
estaria ultrapassando o limite superior de sua memória, conforme pode ser visto na Figura 7: 
Sistemas Operacionais 
Marcio Quirino - 79 
 
 
Figura 7: Proteção de memória com relocação dinâmica. Fonte: SILBERSCHATZ, 2015. 
2. Políticas de alocação de memória 
Políticas de alocação 
As políticas de alocação de memória compreendem dois tipos básicos: 
1. Manter os processos na memória principal durante toda a sua execução. 
2. Mover os processos entre a memória principal e a secundária (tipicamente disco), utilizando 
técnicas de swapping (Permuta)ou de paginação. 
Iniciaremos agora a compreensão dessas políticas de alocação de memória. 
Gerenciamento de memória sem permuta 
Alocação contígua 
Os primeiros sistemas computacionais eram monoprogramados, ou seja, somente um processo de 
usuário por vez estava na memória. Para melhorar essa situação, foi desenvolvido um esquema muito 
simples, no qual a memória principal era compartilhada entre o sistema operacional e o processo de usuário, 
conforme pode ser visto na Figura 8. 
 
Figura 8: Alocação contígua. Fonte: EnsineMe. 
Essa técnica apresenta como desvantagem a limitação do tamanho máximo do programa ao 
tamanho da memória disponível. Para superar essa limitação, foi desenvolvida a primeira técnica de 
permuta, a overlay. 
Overlay 
A técnica de overlay utiliza o conceito de sobreposição, ou seja, a mesma região da memória será 
ocupada por módulos diferentes do processo. 
Sistemas Operacionais 
Marcio Quirino - 80 
 
 
Figura 9: Módulo principal e secundários. Fonte: EnsineMe. 
 
Quando um programa excedia a memória disponível, o programador dividia o código em um módulo 
principal e vários módulos secundários (Figura 9). Para que a técnica pudesse funcionar, era necessário que 
os módulos secundários fossem independentes entre si e qualquer dependência seria apenas em relação 
ao módulo principal. 
 
Figura 10: Carga do módulo principal. Fonte: EnsineMe. 
 
Nesse modelo, o primeiro passo era carregar apenas o módulo principal na memória, permanecendo 
os módulos secundários no disco (Figura 10). 
 
Figura 11: Carga do módulo 1. Fonte: EnsineMe. 
 
O módulo 1 é um módulo secundário, tal como o 2. Estes podem ser requisitados pelo módulo 
principal, e o SO os carregará em memória assim que forem demandados. 
Sistemas Operacionais 
Marcio Quirino - 81 
 
 
Figura 12: Carga do módulo 2. Fonte: EnsineMe. 
 
Após o término da execução do modulo 1, o controle retorna ao módulo principal, que volta a 
executar. Ao necessitar de um recurso do módulo 2, ele solicita sua carga na área de overlay (Figura 12) e 
é colocado em execução. 
Nesse tipo de estrutura, um módulo fica sempre residente (módulo principal) e os demais são 
organizados em uma árvore hierárquica de módulos, mutuamente exclusivos, em relação a sua execução, 
e colocados lado a lado num mesmo nível da árvore, de modo que o mesmo espaço possa ser alocado para 
mais de um módulo, os quais permanecem no disco e serão executados um de cada vez por meio de 
comandos de chamada (call). 
Atenção 
Esse foi o primeiro uso de permuta, mas cabe ao programador escrever o código de forma correta e determinar 
o endereçamento de carregamento dos módulos de overlay. 
Alocação particionada fixa 
Com o advento da multitarefa, apareceu também a necessidade de se manter mais de um processo 
de usuário na memória ao mesmo tempo. Surgiu então a ideia de dividir a memória em partições fixas, 
podendo ser de tamanhos diferentes e, em cada uma, seria alocado um processo de usuário que ali 
coubesse. 
Essas partições eram fixas, estabelecidas na configuração do sistema, e o processo nela permanecia 
até o seu término, quando então ela era liberada para o uso de outro processo que estivesse na fila 
esperando alocação. 
Duas estratégias podem ser adotadas para alocar o processo e estão ilustradas na Figura 13: 
 
Figura 13: Filas de processo e partições fixas. Fonte: TANENBAUM, 2008. 
Sistemas Operacionais 
Marcio Quirino - 82 
 
 
Uma fila por partição: os processos são divididos em várias filas de acordo com o seu tamanho e são 
alocados quando a partição atendida pela fila está disponível (Figura 13a). 
b 
 
Uma única fila de entrada: todos os processos ficam na mesma fila e vão sendo alocados na menor 
partição livre que possa acomodá-los (Figura 13b). 
Este método de gerência de memória baseado em partições fixas gera, de uma forma ou de outra, 
um grande desperdício de memória. Isso acontece porque quando um processo é carregado em uma 
partição sem ocupar todo o seu espaço, o espaço restante não poderá ser utilizado por nenhum outro 
processo. 
Para evitar esse desperdício foi desenvolvido um esquema de gerenciamento e alocação de memória 
dinamicamente, dependendo da necessidade do processo. Esse esquema é conhecido como alocação com 
partições variáveis. 
Alocação com partições variáveis 
Nesta técnica, em vez de particionar a memória em blocos de tamanhos predeterminados... 
Clique nas setas para ver o conteúdo. 
 
Figura 14: Área de memória livre. Fonte: EnsineMe. 
 
A memória de usuário é inicialmente considerada uma única partição livre. 
 
Figura 15: Alocação do processo A. Fonte: EnsineMe. 
 
Sistemas Operacionais 
Marcio Quirino - 83 
 
Ao iniciar o processo A, ele é carregado na memória e o seu tamanho define o tamanho da sua 
partição. 
 
Figura 16: Alocação dos processos B e C. Fonte: EnsineMe. 
 
Os processos B e C, de forma análoga, são carregados no espaço livre ainda disponível, de acordo 
com o ilustrado na Figura 16. 
 
Figura 17: Falta de espaço em memória. Fonte: EnsineMe. 
 
Ao chegar ao processo D, não existe espaço livre contínuo suficiente para que seja carregado. Ele 
deve, então, esperar que um espaço contíguo de tamanho suficiente esteja liberado, assim que o processo 
A termina, logo, o processo D pode ser alocado. 
 
Figura 18: Fragmentação em memória. Fonte: EnsineMe. 
 
Após alocar e desalocar vários processos, a memória pode se fragmentar, por exemplo, no espaço 
entre os processos D e B. 
Sistemas Operacionais 
Marcio Quirino - 84 
 
Para realizar a escolha da partição para a próxima tarefa em fila, podem ser utilizados diversos tipos 
de políticas. Para exemplificar, considere uma situação em que um processo C de 70k precisa ser alocado 
em uma das partições a seguir (figura 19). Assim, serão descritas as formas que podemser utilizadas para 
realizar a alocação de memória. 
 
Figura 19: Ocupação de memória. 
Política Best-Fit 
Procura alocar o processo na partição disponível de tamanho mais próximo ao do processo. Busca 
deixar fragmentos livres menores, mas exige que se percorra todas as partições para descobrir a menor em 
que o processo caiba. No nosso exemplo, será alocado na partição de 80k, gerando um fragmento de 10k, 
conforme visto na Figura 20. 
 
Figura 20: Política Best-Fit. 
Política First-Fit 
Procura alocar o processo na primeira partição onde ele couber. Probabilisticamente, agrupa os 
processos pequenos, separando-os dos grandes, e tem a vantagem de ser mais rápido, pois só percorre as 
partições até encontrar uma em que o processo caiba. No caso do exemplo ilustrado na Figura 21, gera uma 
área livre de 80k. 
Sistemas Operacionais 
Marcio Quirino - 85 
 
 
Figura 21: Política First-Fit. 
Política Worst-Fit 
Procura alocar o processo na maior partição disponível onde ele couber. Intuitivamente, sempre 
caberá mais um processo pequeno no espaço resultante. Tem como desvantagem ter que percorrer todas 
as partições até encontrar a maior. No caso do exemplo, gera uma área livre de 130k, como visto na Figura 
22: 
 
Figura 22: Política Worst-Fit. 
Fragmentação externa e interna 
A diferença principal entre as partições fixas e as variáveis é que nas variáveis o número, tamanho 
e posição das partições variam ao longo do tempo, conforme é possível observar na Figura 23: 
Sistemas Operacionais 
Marcio Quirino - 86 
 
 
Figura 23: Fragmentação de memória nas partições variáveis. Fonte: TANENBAUM, 2008. 
A longo do tempo, esse processo pode acarretar fragmentação externa, ou seja, entre as partições 
podem ser gerados pequenos pedaços livres que, no seu todo, poderiam atender à necessidade de memória 
de um processo, mas, como não são contíguos, não permitem a alocação. 
Outro tipo de fragmentação é a interna, que você pode compreender a seguir: 
Exemplo 
Considere uma área livre de 16.484 bytes e que o próximo processo solicite 16.480 bytes. Se for alocado 
exatamente o bloco solicitado, ficaremos com uma fragmentação externa de 4 bytes. O esforço para fazer o controle 
de uma lacuna tão pequena não compensa. Dessa forma, a solução geral para esse tipo de problema é alocar todo o 
bloco para o processo, que resultará numa área não utilizada de 4 bytes dentro dele, correspondendo a uma 
fragmentação interna. 
Uma possível solução para a fragmentação externa seria realizar a compactação da memória, que 
compreende mover todos os blocos ocupados para uma das extremidades do espaço de endereçamento 
físico, resultando na geração de um grande bloco livre. 
Apesar de parecer uma solução tentadora, ela não é normalmente utilizada porque o seu custo de 
processamento é alto. 
Outra solução possível seria permitir que o espaço de endereçamento do processo não seja contíguo, 
possibilitando, dessa forma, que ele receba blocos de memória disponíveis em qualquer parte do espaço de 
endereçamento. Essa ideia, com o swap, é a base do funcionamento da paginação e da segmentação que 
serão estudados mais adiante. 
Gerenciamento de memória com permuta 
Swap de memória 
Um processo deve estar na memória para ser executado. Entretanto, nada impede que, enquanto 
ele está bloqueado ou em espera, ele seja retirado da memória principal e transferido para a memória 
secundária e novamente carregado, quando chegar sua vez de ser novamente executado. Isto é o que 
chamamos de swapping. 
O uso do swapping permite aumentar o grau de multiprogramação, pois permite que a memória total 
dos processos ultrapasse a memória física disponível no sistema, o que era impossível no esquema de 
partições. 
Observe a Figura 24, que ilustra a situação em que temos o processo E esperando por um espaço 
livre contíguo onde ele caiba. 
No esquema de partições ele necessitaria esperar o término da execução de um dos processos em 
memória, porém, se o sistema utiliza swapping, é possível retirar um processo que não esteja em execução 
e que ocupe o meio de uma partição. No caso, o processo A (swap out) o coloca no disco, atribui a nova 
Sistemas Operacionais 
Marcio Quirino - 87 
 
partição disponível ao processo que estava esperando e, posteriormente, atribui outra partição (swap in) ao 
processo que foi desalojado. 
 
Figura 24: Swapping. Fonte: TANENBAUM, 2008. 
Como é possível perceber, essa técnica utiliza relocação dinâmica e, portanto, os processos não 
podem utilizar endereçamento absoluto. 
As grandes vantagens do swap são: 
• Maior compartilhamento da memória (maior throughput de tarefas). 
• Menor fragmentação de memória. 
• Boa técnica para ambientes com processos pequenos e poucos usuários. 
A desvantagem é o tempo gasto no swap in e no swap out. 
Exemplo 
Suponha que um processo que tem que ser retirado da memória possua 200MB (swap out) e que um processo 
a ser carregado tenha 150MB (swap in). Se considerarmos que o HD possui uma velocidade de escrita de 50MB/s e 
de leitura de 100MB/s o swap out demoraria 4 segundos e o swap in 1,5 segundos. Portanto, a operação total, sem 
considerar outros tempos envolvidos, demoraria 5,5 segundos, uma eternidade em termos computacionais. 
Devido a essa perda de tempo, essa técnica não é utilizada em sistemas modernos. Nos sistemas 
operacionais atuais, variantes otimizadas no tempo de escrita/leitura, tais como a paginação, são largamente 
implementadas. 
Gerenciamento de espaço livre 
Para que as diversas políticas de alocação possam funcionar é necessário que o SO controle os 
espaços livres na memória e onde cada processo está alocado, utilizando algumas técnicas que serão 
estudadas a seguir. 
Gerenciamento de memória com mapas de bits 
Nesta técnica, a memória é dividida em unidades de alocação e, para cada unidade, existe um bit no 
mapa de bits marcado como 0 se a unidade estiver livre, e com 1 se estiver ocupada. 
Neste esquema, a definição do tamanho da unidade é extremamente importante. Quanto menor for 
a unidade, maior será o mapa e vice-versa. Entretanto, também existe outra implicação: se a unidade for 
grande e o tamanho do processo não for múltiplo do tamanho da unidade, no último bloco alocado haverá 
fragmentação interna. 
Atenção 
O principal problema desse tipo de gerenciamento é que, quando for necessário trazer um processo de n 
unidades para a memória, o gerenciador da memória terá que encontrar uma sequência de n bits 0 consecutivos no 
mapa, o que é uma operação lenta por sua própria natureza. 
Sistemas Operacionais 
Marcio Quirino - 88 
 
Observe a Figura 25, que mostra a gerência de espaço livre funcionando: 
 
Figura 25: Memória e mapeamento de espaço livre. Fonte: TANENBAUM, 2008. 
• A letra (a) mostra uma parte da memória com cinco processos e três lacunas. Os tracinhos 
mostram as unidades de alocação de memória. 
• A letra (b) mostra o mapa de bits correspondente. 
• A letra (c) apresenta as mesmas informações como uma lista encadeada. 
Gerenciamento de memória com listas encadeadas 
A outra forma de gerenciamento é a criação de uma lista encadeada, na qual cada nó da lista 
corresponde a um segmento de memória alocada – indicada na Figura 25(c) pelo P – ou livre – indicada por 
L. Além da indicação do status, o nó armazena o endereço inicial do segmento e o seu tamanho em unidades 
de alocação. 
Nesse exemplo, a lista de segmentos está ordenada pelo endereço. Ordenando dessa maneira, 
quando um processo termina a lista deve ser atualizada. Um processo que termina normalmente tem dois 
vizinhos, exceto se for o primeiro ou o último da lista, que podem ser processos ou lacunas. 
Essa situação gera quatro possíveis combinações a serem tratadas e que são exibidas na Figura 26. 
Considerando que o processo X terminou, deve-se: 
 
Figura 26: Gerência da lista encadeada. Fonte: TANENBAUM, 2008. 
1. Na situação (a), atualizar a lista exigesubstituir um P por um L. 
2. Nas situações (b) e (c), duas entradas são aglutinadas em uma e a lista se torna uma única 
entrada mais curta. 
3. Na situação (d), três entradas são aglutinadas e dois itens são removidos da lista. 
Sistemas Operacionais 
Marcio Quirino - 89 
 
3. Funcionamento da memória virtual 
Memória virtual 
Como vimos anteriormente, o espaço de endereçamento lógico de um programa tem que ser 
mapeado em um espaço de endereçamento físico de memória. 
De fato, essa correspondência pode ser deixada totalmente a cargo do SO, de forma que o programa 
não tenha nenhuma responsabilidade em se ater a um determinado tamanho de memória física disponível. 
Assim, o conjunto de endereços que um programa pode endereçar pode ser muito maior que a 
memória física disponível para o processo em um determinado momento, até mesmo mais que o total de 
memória fisicamente disponível na máquina. 
A esse conjunto de endereços chamamos de espaço de endereçamento virtual. Ao conjunto de 
endereços reais de memória denominamos espaço de endereçamento real. 
Assim, como os programas podem ser maiores que a memória física, somente uma parte de cada 
programa precisa estar na memória durante a execução. As partes que não são necessárias em um 
determinado instante ficam em disco e somente são carregadas quando se tornarem necessárias. 
Todo o processo é transparente para o usuário e também para os compiladores e link-editores, pois 
estes trabalham apenas com o espaço de endereçamento virtual. Apenas o SO se incumbe de carregar ou 
descarregar as partes necessárias e mapeá-las no espaço de endereçamento real durante a execução. 
Como consequência desse mapeamento, o programa não precisa estar nem mesmo em regiões 
contíguas de memória. Naturalmente, o nível de fracionamento do programa deve ser escolhido de forma a 
não comprometer o desempenho, na medida em que a tarefa de mapeamento é feita pelo SO com recursos 
de hardware. 
Assim, a memória (tanto a virtual como a real) é dividida em blocos, e o SO mantém tabelas de 
mapeamento para cada processo, que relacionam os blocos da memória virtual do processo com os blocos 
da memória real da máquina. 
A Figura 27 mostra essa ideia. Note que o espaço de endereçamento virtual é muito maior que a 
memória física. Observe ainda que o processo é endereçado por partes, no caso páginas, e elas são lidas 
do disco para a memória e gravadas no disco, em um processo chamado paginação, uma implementação 
da ideia de swap e que estudaremos a seguir. 
 
Figura 27: Memória virtual. Fonte: SILBERSCHATZ, 2015. 
Sistemas Operacionais 
Marcio Quirino - 90 
 
Paginação 
Na paginação, o espaço de endereços é dividido em blocos de igual tamanho que chamamos de 
páginas. A memória principal também é dividida em blocos de mesmo tamanho (igual ao tamanho da página) 
denominados molduras. 
Esses blocos de memória real são compartilhados pelos processos, de forma que a qualquer 
momento um determinado processo terá algumas páginas residentes na memória principal (as páginas 
ativas), enquanto as restantes utilizarão a memória secundária (as páginas inativas). 
O mecanismo da paginação possui duas atribuições: 
• Executar a operação de mapeamento, isto é, determinar qual a página referenciada e em que 
bloco de memória (se for o caso) ela se encontra. 
• Transferir páginas da memória secundária para os blocos da memória principal (quando for 
requerido) e guardá-las de volta na memória secundária quando elas não estiverem em uso. 
Observe a Figura 28, que apresenta o esquema de paginação. Nela podemos ver que o processo foi 
dividido em 4 páginas (0 a 3), a tabela de páginas que as associa com os frames e a alocação das páginas 
na memória. 
 
Figura 28: Paginação. Fonte: SILBERSCHATZ, 2015. 
Na paginação, o hardware determina tanto o tamanho do quadro como o da página, sendo que o 
tamanho da página é sempre uma potência de 2 variando normalmente entre 512 bytes e 2KB. O uso de 
potências de 2 visou facilitar o mapeamento dos endereços virtuais para os físicos. 
Controle de espaço livre 
Quando um novo processo chega ao sistema para ser executado, o seu tamanho é analisado em 
páginas. Como cada página do processo necessita de um quadro, se, por exemplo, ele possui 4 páginas, 
pelo menos 4 quadros devem estar livres. A forma mais fácil de o SO realizar o controle das áreas livres é 
mantendo uma lista dos quadros livres. Como todos os quadros possuem o mesmo tamanho e o processo 
pode ser alocado de forma não contígua, a lista não necessita estar ordenada, o que facilita muito a sua 
manutenção. 
É exatamente esta situação que se pode observar na Figura 29(a), que mostra os quadros livres (em 
tom cinza) e ocupados (em tom azul) na memória física, o novo processo de 4 páginas e a lista de quadros 
livres com 5 quadros (14, 13, 18, 20 e 15). 
Sistemas Operacionais 
Marcio Quirino - 91 
 
A partir desta situação, a página 0 do processo será alocada no primeiro quadro da lista, o 14, a 
segunda no 13, e assim, sucessivamente, sendo preenchida a tabela de páginas do processo e gerando o 
cenário que pode ser observado na Figura 29(b). 
 
Figura 29: Paginação e controle de quadros livres. Fonte: SILBERSCHATZ, 2015. 
Proteção de memória 
Em um ambiente paginado, a proteção de memória é provida pelo acréscimo de bits de proteção 
associados a cada quadro na tabela de páginas. 
Um bit pode definir que uma página é apenas de leitura ou se permite também a gravação. 
Além dos bits já descritos, normalmente um outro bit denominado válido-inválido é acrescido à tabela 
para estabelecer se aquela página está no espaço de endereçamento lógico do programa (acesso legal) ou 
não (acesso ilegal). 
Considere a situação da Figura 30. Ela nos mostra um sistema com espaço de endereçamento de 
14 bits (0 a 16383) e um processo que usa apenas os endereços de 0 a 10468. Considerando um tamanho 
de página de 2KB, o processo possui 6 páginas, apesar de ter uma tabela de páginas com mais entradas 
possíveis. 
Na tabela de páginas, apesar de o processo possuir somente 6 delas, as entradas referentes às 
páginas 6 e 7 estão com o número de quadro 0, o que faria com que uma referência à página 7 gerasse 
uma exceção para o SO. 
 
Figura 30: Proteção de memória. Fonte: SILBERSCHATZ, 2015. 
Sistemas Operacionais 
Marcio Quirino - 92 
 
Paginação sob demanda 
A ideia básica da paginação sob demanda é carregar na memória somente páginas que forem 
referenciadas na execução. 
Obviamente, em um primeiro momento, somente a página inicial do processo será carregada e à 
medida que as instruções fizerem referências a outras páginas, elas serão carregadas. Essa abordagem faz 
com que páginas que nunca foram referenciadas jamais sejam carregadas na memória. 
E como funciona essa demanda? Como se sabe, o número de blocos alocados a um processo é 
menor do que o número de páginas que ele usa. Por isso, é possível que um endereço de programa 
referencie uma página ausente. Nesse caso, a entrada da tabela correspondente estará “vazia” e uma 
interrupção do tipo page fault é gerada sempre que uma página inativa é requerida e causa a ação 
descrita na Figura 31. 
 
Figura 31: Paginação sob demanda. Fonte: SILBERSCHATZ, 2015. 
Caso não tenha entendido o que aconteceu, segue a explicação: 
Resumindo 
A interrupção faz com que o mecanismo da paginação inicie a transferência da página ausente da memória 
secundária para um dos blocos da memória principal e atualize a tabela de páginas. O processo muda de estado, 
ficando bloqueado até que a transferência termine. A posição ocupada por uma página na memória secundária é 
guardada em uma tabela separada ou na própria tabela de páginas. Se não houver nenhum bloco de memória 
disponível, então é necessário desocupar um dos blocos para a página, cuja presença está sendo solicitada. A escolha 
do bloco é função do algoritmo de troca, conforme será visto adiante.Working set 
O conjunto das páginas mais acessadas por um determinado processo 
Políticas de paginação 
Para minimizar a ocorrência de page faults surgiu o conceito de working set. Assim, quando um 
programa começa a executar, a possibilidade de que ele requisite páginas que não estejam na memória é 
muito grande. Entretanto, à medida que mais páginas vão sendo carregadas, a ocorrência de page faults vai 
diminuindo devido ao princípio da localidade dos programas. Assim, cabe ao SO definir um conjunto de 
páginas que devem ficar carregadas, sabendo que se trata de um compromisso entre capacidade e 
velocidade. 
Quanto mais páginas carregadas no working set, menor o risco de geração de page fault, logo, 
melhor é o desempenho. Em compensação, quanto mais páginas no working set, menos processos podem 
estar carregados ao mesmo tempo. 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 93 
 
Definido o working set, resta definir qual deve ser a página retirada da memória quando ocorre 
um page fault, pois uma página precisa ser carregada e não existe quadro livre. Esta decisão pode obedecer 
a várias políticas. 
Entretanto, antes de descartar qualquer página, o SO precisa saber se houve alguma alteração nela 
enquanto ela esteve na memória. Se houve, então essa página precisa ser salva em disco antes de ser 
descartada para que nenhum dado se perca. Neste caso, o SO mantém um bit na tabela de páginas 
chamado Bit de Modificação. Caso o bit indique que houve mudança, a página é salva em disco, onde 
poderá ser futuramente resgatada. 
As políticas de liberação de páginas são: 
A. Página aleatória 
Escolhe-se simplesmente qualquer página. A desvantagem é que pode-se escolher uma página 
que seja muito acessada. 
B. First-in-first-out (FIFO) 
Retira-se a página carregada há mais tempo. A desvantagem é que pode retirar páginas que 
sejam acessadas periodicamente. 
C. Least-recently-used (LRU) 
Retira-se a página utilizada pela última vez há mais tempo. A desvantagem é o overhead causado 
pela necessidade de, a cada acesso, atualização do momento em que a página foi acessada. 
D. Not-recently-used (NRU) 
A página não utilizada nos últimos k acessos é substituída. A desvantagem também é o overhead 
causado pela necessidade de, a cada acesso, atualizar um contador de acessos à página. 
E. Least-frequently-used (LFU) 
Escolhe-se a página que tenha o menor número de acessos descritos em um contador de 
acessos. A ideia é manter na memória as páginas que são muito acessadas. Entretanto, o 
problema é que páginas recém-carregadas no working set terão baixo número de acessos e 
serão indesejavelmente cotadas para retirada. 
Sistemas reais, como o Linux, implementam normalmente alguma variação da LRU a partir de 
algoritmos que buscam se aproximar desta política. Um dos mais comumente usados é o algoritmo de 
segunda chance. 
Algoritmo de segunda chance 
Também conhecido como algoritmo do relógio, ele busca uma aproximação ao LRU. Para isso, na 
tabela de páginas são acrescidos bits de referência associados a cada uma de suas entradas. 
Inicialmente, todos os bits são desligados (posicionados com 0) pelo sistema operacional. Quando 
um processo de usuário é executado e uma página é referenciada, o bit associado a ela é ligado (com 1) 
pelo hardware. Após algum tempo, podemos determinar as páginas que têm sido usadas ou não usadas 
examinando os bits de referência, embora sem saber a ordem de uso. 
Comentário 
O algoritmo utiliza uma política de substituição FIFO, mas com uma diferença: quando uma página é 
selecionada para substituição, antes de fazer a troca verificamos seu bit de referência. Se o seu valor for zero, fazemos 
a substituição; se for 1, damos à página uma segunda chance zerando o seu bit e passamos à próxima página. Esse 
método assegura que se uma página for sempre referenciada, ela nunca sairá da memória. 
Sistemas Operacionais 
Marcio Quirino - 94 
 
Este algoritmo é normalmente implementado como uma fila circular (Figura 32) onde um ponteiro (o 
ponteiro do relógio, daí seu nome) indica a página que deve ser substituída a seguir. Quando um quadro é 
necessário, o ponteiro avança até encontrar uma página com bit de referência 0. Conforme ele avança, os 
bits de referência são zerados (Figura 32a). 
Uma vez que uma página vítima seja encontrada, ela é substituída e a nova página é inserida na 
fila circular nessa posição (Figura 32b). 
Página vítima 
Página vítima é a candidata a sair da memória. Ele faz a busca na fila circular: ao encontrar uma página 
candidata à remoção (página vítima), ele substitui. 
Observe que, na pior das hipóteses, quando todos os bits estão ligados, o ponteiro circula a fila 
inteira, dando a cada página uma segunda chance. Ele zera todos os bits de referência antes de selecionar 
a próxima página para substituição. 
A substituição da segunda chance degenera para uma substituição FIFO se todos os bits estiverem 
ligados. 
 
Figura 32: Algoritmo de segunda chance. Fonte: SILBERSCHATZ, 2015. 
Um aperfeiçoamento que pode ser realizado neste algoritmo é levar em conta também o valor de bit 
de modificação. Dessa forma, a página pode estar em uma destas quatro categorias, da mais baixa para a 
mais alta: 
A. (0, 0) nem recentemente utilizada, nem modificada 
Melhor página para a substituição. 
B. (0, 1) não recentemente utilizada, mas modificada 
Não é uma opção tão boa porque a página terá que ser gravada em disco antes da substituição. 
C. (1, 0) recentemente utilizada, mas não modificada 
Provavelmente será usada outra vez em breve. 
D. (1, 1) recentemente utilizada e modificada 
Provavelmente será usada de novo em breve e terá que ser gravada em disco antes de poder 
ser substituída. 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 95 
 
Nesta implementação, continuamos utilizando uma fila circular, mas em vez de verificar o bit de 
referência, determinamos a categoria da página e substituímos a primeira página da categoria mais baixa. 
A principal diferença entre esse algoritmo e o algoritmo do relógio mais simples é que aqui damos 
preferência à substituição de páginas que não foram modificadas, para reduzir o número de operações de 
gravação requeridas, já que páginas que não foram modificadas ao serem substituídas não necessitam de 
gravação no disco. 
Segmentação 
Devido ao grande número de page faults da paginação, a segmentação surgiu como uma alternativa 
de gerência de memória, na qual o programa não mais é dividido em blocos de comprimentos fixos (as 
páginas), mas, sim, em segmentos de comprimentos variados com um sentido lógico. Ou seja, a paginação 
procedia uma divisão física do programa e, às vezes, isso levava a um número muito grande de page faults 
por não observar suas características lógicas. 
A segmentação busca aproveitar exatamente essas características, agrupando num segmento partes 
do programa que se referenciam mutuamente e que, quando trazidas à memória, estarão todas juntas 
evitando o que nesse caso é chamado de segment faults com tanta frequência. 
Nesse esquema, o espaço de endereços torna-se bidimensional: endereços de programa são 
denotados pelo par (nome do segmento, endereço dentro do segmento). 
Para facilitar a implementação do mecanismo de transformação de endereços, o SO troca o nome 
do segmento por um número, quando o segmento é referenciado pela primeira vez. 
Considerando o par (s,d) como sendo um endereço de programa generalizado, onde s = número do 
segmento e d = endereço dentro do segmento, então o esquema de geração seria o apresentado na Figura 
33: 
 
Figura 33: Segmentação. Fonte: SILBERSCHATZ, 2015. 
Conforme podemos ver, a transformação de endereço é realizada por intermédio de uma tabela de 
segmentos (uma tabela para cada processo). A “s-ésima” entrada da tabela contém o tamanho (l) e a posição 
inicial (a) da memória, onde o “s-ésimo” segmento foi carregado. 
As entradasda tabela são chamadas de Descritores de Segmento. O algoritmo de mapeamento é: 
1. Extrair endereço de programa (s,d). 
2. Usar “s” para indexar tabela de segmentos. 
3. Retirar o endereço inicial do segmento (a). 
4. Se d < 0 ou d > l então “violação de memória”. 
Sistemas Operacionais 
Marcio Quirino - 96 
 
5. a + d é o endereço requerido. 
A busca de espaços para um segmento a ser trazido à memória nos leva novamente aos problemas 
de gerência por partições variáveis. A diferença aqui é que o espaço contíguo só é necessário para o 
segmento e não para todo o processo. 
A diferença principal entre a segmentação e a paginação é que a primeira busca uma divisão lógica 
do espaço de endereçamento do processo, enquanto a segunda busca uma divisão física desse mesmo 
espaço. Ambas se engajam na implementação de uma política de memória virtual de um único nível. Páginas 
têm seu tamanho determinado pelo tamanho da palavra, enquanto segmentos têm seu tamanho 
determinado pelo tamanho da memória disponível. 
4. Como o Linux realiza a sua gerência de memória 
Gerenciamento de memória no Linux 
A gerência de memória no Linux envolve dois aspectos distintos, cada um efetuado por um 
componente específico: 
• A alocação e liberação da memória física – páginas, grupos de páginas e pequenos blocos 
de RAM. 
• A manipulação da memória virtual – mapeamento da memória física para o espaço de 
endereçamento de processos em execução. 
Gerenciamento da memória física no Linux 
Em razão de restrições específicas do hardware, o Linux divide a memória física em quatro zonas ou 
regiões diferentes que, dependendo da arquitetura, correspondem a especificações diferentes. 
Em uma arquitetura Intel x86 de 32 bits elas são: 
A. ZONE_DMA 
Para dispositivos ISA que somente podem acessar os primeiros 16MB da memória para fazer 
acesso direto. 
B. ZONE_DMA32 
Para dispositivos que podem acessar os primeiros 4GB da memória em operações de DMA. 
C. ZONE_HIGHMEM 
Corresponde à memória alta (high memory) que não está mapeada para o kernel do sistema, 
que, nesta arquitetura, corresponde aos primeiros 896MB do espaço de endereçamento, ficando 
todo o espaço restante até 4GB disponível para uso. 
D. ZONE_NORMAL 
Corresponde a todo o resto da memória. 
Importante: em modernos sistemas de 64 bits, como o Intel x86 de 64 bits, existe uma pequena 
ZONE_DMA de 16 MB para ser utilizada por sistemas legados e todo o resto fica na ZONE_NORMAL, sem 
ZONE_HIGHMEN ou ZONE_DMA32. 
A Figura 34 mostra o mapeamento entre as zonas e os endereços físicos na arquitetura do Intel x86 
de 32 bits. 
 
Sistemas Operacionais 
Marcio Quirino - 97 
 
Zona Memória física 
ZONE_DMA < 16 MB 
ZONE_NORMAL 16 .. 896 MB 
ZONE_HIGHMEM > 896 MB 
Figura 34: Relacionamento entre endereços físicos e zonas no Intel x8632. Fonte: SILBERSCHATZ, 2015. 
O kernel mantém uma lista das páginas livres em cada zona e, ao receber uma solicitação de 
memória, faz o atendimento disponibilizando as páginas na zona apropriada. 
Cada zona possui seu próprio alocador de páginas que é o responsável por alocar e desalocar as 
páginas físicas. 
Memória virtual no Linux 
O mecanismo de memória virtual é o responsável por manter o espaço de endereçamento disponível 
para cada processo. Para fazer o gerenciamento são mantidos, para cada processo, duas visões diferentes: 
A. Visão lógica 
Descreve as instruções que o sistema de memória virtual recebeu relacionadas com o layout do 
espaço de endereçamento. Nessa visão, o espaço de endereçamento consiste em um conjunto 
de regiões não sobrepostas, cada uma representando um subconjunto alinhado e contínuo de 
páginas do espaço de endereçamento. As regiões de cada espaço de endereçamento são 
vinculadas em uma árvore binária balanceada para permitir a busca rápida da região 
correspondente a qualquer endereço virtual. 
B. Visão física 
Corresponde a entradas nas tabelas de páginas de hardware do processo, que identificam a 
locação corrente exata de cada página de memória virtual, esteja ela em disco ou na memória 
física. 
Regiões de memória virtual 
O Linux trabalha com vários tipos de regiões de memória virtual. 
Uma região de memória virtual tem normalmente um arquivo associado a ela e funciona como uma 
porta de entrada para uma seção do arquivo de paginação. 
Sempre que o processo faz referência a uma página da região, a entrada correspondente na tabela 
de páginas é preenchida com o endereço de uma página do cache de páginas do kernel com o valor do 
deslocamento apropriado no arquivo. 
Outro aspecto importante nas regiões é como elas tratam as gravações. Uma região pode ser 
mapeada de forma compartilhada ou privada para o espaço de endereçamento de um processo. 
Você sabia 
Se um processo gravar em uma região mapeada privadamente, então, o paginador detectará que uma cópia 
após a gravação é necessária para manter as alterações locais ao processo. Por outro lado, gravações em uma região 
compartilhada resultam na atualização do objeto mapeado para essa região, de modo que a alteração seja 
imediatamente visível por qualquer outro processo que esteja mapeando esse objeto. 
Tempo de vida de um espaço de endereçamento virtual 
Duas situações geram a criação de um novo espaço de endereçamento virtual: 
A. Quando um processo executa um novo programa com a chamada de sistema exec( ) 
Sistemas Operacionais 
Marcio Quirino - 98 
 
Neste caso, o processo recebe um novo espaço de endereçamento virtual totalmente vazio. A 
rotina de carga do programa faz o mapeamento do espaço de endereçamento com regiões de 
memória virtual. 
B. Quando um novo processo é criado pela chamada de sistema fork( ) 
Neste caso, é realizada uma cópia completa do espaço de endereçamento virtual do processo 
pai para o conjunto das tabelas de páginas criadas para o processo filho, copiadas diretamente 
nas tabelas do filho. Portanto, após a ramificação, o pai e o filho compartilham as mesmas 
páginas físicas de memória em seus espaços de endereçamento. 
Permuta e paginação 
Como se sabe, uma atividade extremamente importante na memória virtual é a execução 
do pagein e pageout. 
Como acontece nos demais sistemas de paginação, o Linux trabalha em dois passos: 
• Decide qual página deve ser substituída na memória e se é necessário gravá-la em disco. 
• Carrega a nova página no quadro liberado pela página que foi substituída. 
No Linux, a substituição de páginas utiliza uma política similar ao algoritmo do relógio, modificada 
para trabalhar com múltiplos ciclos. 
Cada página possui uma “idade” que é ajustada a cada ciclo do relógio. A idade indica há quanto 
tempo a página foi alocada e/ou o nível de atividade que a página experimentou recentemente. Dessa forma, 
páginas acessadas com frequência recebem um valor de idade mais alto e a idade de páginas acessadas 
raramente cairá em direção a zero a cada ciclo. 
Essa quantificação da idade permite que o paginador selecione as páginas a serem extraídas com 
base na política da menos frequentemente utilizada (LFU). 
Você sabia 
No tocante à Memória virtual do Kernel, o Linux reserva para seu próprio uso interno uma região constante do 
espaço de endereçamento virtual de cada processo. As entradas da tabela de páginas que são mapeadas para essas 
páginas do kernel são marcadas como protegidas, para que as páginas não sejam visíveis ou modificáveis quando o 
processador estiver sendo executado em modalidade de usuário. 
Execução e carga de programas de usuário 
A execução de programas de usuário pelo kernel do Linux é disparada pela chamada de sistema 
exec( ), que instrui o kernel a executar um novo programa dentro do processo em curso, substituindo 
completamente o contexto de execução corrente pelo contexto inicial do novo programa. 
Para fazer a carga, é invocado o carregador que pode inicialmente fazer ou não a alocação na 
memória física do processo, mas sempre realiza o mapeamento do programapara a memória virtual. 
Mapeamento de programas para a memória 
No Linux, o carregador binário não carrega um arquivo desse mesmo sistema na memória física. Em 
vez disso, as páginas do arquivo binário são mapeadas para regiões de memória virtual. É utilizada a técnica 
da Paginação sob Demanda, de forma que somente quando a página for necessária é que ele será 
efetivamente alocado na memória física. 
É responsabilidade do carregador binário do kernel estabelecer o mapeamento inicial da memória. 
Um arquivo binário no formato ELF consiste em um cabeçalho seguido por várias seções de páginas 
alinhadas. O carregador ELF funciona lendo o cabeçalho e mapeando as seções do arquivo para regiões 
separadas da memória virtual. 
Sistemas Operacionais 
Marcio Quirino - 99 
 
A Figura 35 mostra o layout típico de regiões de memória estabelecidas pelo carregador ELF. Em 
uma região reservada em uma extremidade do espaço de endereçamento reside o kernel, em sua própria 
região privilegiada de memória virtual inacessível a programas normais de modalidade de usuário. 
O resto da memória virtual fica disponível para aplicações que podem usar as funções de 
mapeamento da memória do kernel para criar regiões que mapeiem uma parte de um arquivo ou que estejam 
disponíveis para dados de aplicações. 
 
Figura 35: Layout de memória de um arquivo ELF. Fonte: SILBERSCHATZ, 2015. 
A função do carregador é estabelecer o mapeamento inicial da memória para permitir que a execução 
do programa comece. As regiões que precisam ser inicializadas incluem a pilha e as regiões de texto e 
dados do programa. 
A pilha é criada no topo da memória virtual de modalidade de usuário; ela cresce para baixo em 
direção a endereços de numeração menor e inclui cópias dos argumentos e variáveis de ambiente fornecidas 
ao programa na chamada de sistema exec( ). 
As outras regiões são criadas perto da extremidade inferior da memória virtual e incluem: 
As seções do arquivo binário que contêm texto de programas ou dados apenas de leitura, que são 
definidas como apenas leitura e protegidas contra gravação. 
Dados inicializados ou não que podem sofrer gravação são alocados a seguir. 
O heap, que é uma área de tamanho variável e que armazena os dados em tempo de execução. 
Tem seu limite apontado por brk, o que permite sua expansão ou retração. 
Uma vez que esses mapeamentos tenham sido estabelecidos, o carregador inicializa o registrador 
de contagem de programas do processo com o ponto inicial registrado no cabeçalho ELF, e o processo pode 
ser incluído no escalonador. 
Vinculação estática e dinâmica 
Uma vez que o programa foi carregado e escalonado para o processador, todos os conteúdos 
necessários para sua execução já estarão no seu espaço de endereçamento virtual. Entretanto, a maior 
parte dos programas utiliza códigos de bibliotecas do sistema que também devem ser carregados. 
Exemplo 
Uma maneira simples de lidar com isso é embutir diretamente no executável do programa o código da 
biblioteca, o que é realizado pelo ligador durante a geração do executável. Dessa forma, o programa é vinculado 
Sistemas Operacionais 
Marcio Quirino - 100 
 
estaticamente às suas bibliotecas e executáveis. Com este tipo de vinculação podem iniciar a execução imediatamente 
assim que carregados. 
Essa abordagem, entretanto, tem como principal desvantagem o fato de que cada programa gerado 
deve conter cópias exatas das mesmas funções comuns das bibliotecas do sistema. É muito mais eficiente, 
tanto em termos de memória física como também de uso de espaço em disco, carregar as bibliotecas do 
sistema na memória apenas uma vez. Isso pode ser feito utilizando os recursos de vinculação dinâmica 
existentes no Linux. 
Cada programa vinculado dinamicamente contém uma pequena função vinculada estaticamente que 
é chamada quando o programa é iniciado. Essa função estática apenas mapeia a biblioteca de vinculação 
para a memória e executa o código contido na função. 
A biblioteca de vinculação determina as bibliotecas dinâmicas requeridas pelo programa e os nomes 
das variáveis e funções necessárias destas por meio da leitura das informações contidas em seções do 
binário ELF. Ela mapeia, então, as bibliotecas para o meio da memória virtual e resolve as referências para 
os símbolos contidos nas mesmas. Não importa para que local exato da memória essas bibliotecas 
compartilhadas sejam mapeadas, elas são compiladas em código independente de posição, que pode ser 
executado em qualquer endereço da memória. 
Utilitários e comandos para gerenciar a memória do sistema Linux 
Para gerenciar a memória de um sistema Linux podem ser utilizados diversos comandos, inclusive 
utilitários para esse propósito, conforme será apresentado na sequência. Ao final deste módulo é 
disponibilizado o vídeo em que os pontos abordados são executados na prática, em uma máquina virtual. 
Obtendo informações pela linha de comando 
Para estes exemplos usaremos uma máquina virtual com Ubuntu instalado. 
 
Captura de tela da execução do comando htop. 
O Linux provê uma série de comandos de linha que obtêm informações do sistema de memória. 
Vejamos os principais: 
A. FREE 
O comando free exibe informações precisas sobre o uso dos recursos de memória do sistema. 
Neste exemplo, pode-se observar uma máquina virtual com aproximadamente 4GB (3996 MB) 
de RAM e tendo em uso 1235MB, sobrando 2338MB disponíveis. 
O comando mostra ainda que temos uma área de 448MB para swap da qual foram utilizados 
8MB. 
 
O argumento -m faz com que as informações venham em MB. 
 
Sistemas Operacionais 
Marcio Quirino - 101 
 
B. TOP 
Este comando mostra informações a respeito dos processos rodando em sua máquina, incluindo 
o uso da memória. 
 
C. VMSTAT 
Este comando mostra a situação da memória virtual da máquina. 
 
D. GETCONF PAGESIZE 
O comando getconf PAGESIZE mostra o tamanho da página no sistema de memória virtual que, 
neste caso, é de 4096 bytes, ou seja, 4KB. 
 
E. SWAPON 
O comando swapon mostra informações a respeito do arquivo de swap. 
 
Utilitários para acesso à informação 
Vários utilitários que podem ser chamados na linha de comando ou por meio da interface gráfica 
podem ser utilizados para monitorar o uso da memória do Linux. Com exceção do monitor do sistema, todos 
os outros precisam ser instalados no Ubuntu, pois não existem como padrão. 
Htop 
Esse aplicativo htop é uma evolução do comando top e exibe de forma interativa as informações do 
sistema. 
Ele é chamado na linha de comando. 
 
Captura de tela do Software htop. 
Sistemas Operacionais 
Marcio Quirino - 102 
 
Após a chamada, ele carrega sua interface, na qual, em sua parte superior, temos informações 
agregadas e, na parte inferior, a lista de processos com suas informações de CPU, memória etc. 
 
Captura de tela do Software htop. 
Neste aplicativo, as cores que aparecem no resumo na parte superior possuem significado. 
 
Captura de tela do Software htop. 
Sendo assim, observa-se o seguinte: 
A. CPU 
• Verde: Threads rodando com prioridade normal. 
• Azul: Threads rodando com baixa prioridade. 
• Vermelho: Threads rodando em favor do kernel. 
B. Memória 
• Verde: Memória em uso pelas aplicações. 
• Azul: Buffers em utilização. 
• Amarelo / Laranja: Cache. 
C. Swap 
• Vermelha: Representa a quantidade de memória swap utilizada 
Essas informações podem ser obtidas ainda apertando F1 
Sistemas Operacionais 
Marcio Quirino - 103 
 
 
Captura de tela do Software htop. 
Ksysguard 
O utilitário ksysguard é outro que pode ser chamado na linha de comando e que não vem instalado 
por padrão. 
 
Captura de tela da execução do utilitário ksysguard. 
Ele possui uma interface gráfica que mostra as informações do sistema. 
Na aba Tabela de Processos, ele mostra todos os existentes no sistema e as informações de CPU e 
memória. 
 
Captura de tela do Software htop. 
Na aba Carga do Sistema, ele mostrade forma gráfica a utilização pelos processos. 
Sistemas Operacionais 
Marcio Quirino - 104 
 
 
Captura de tela do Software htop. 
Monitor do Sistema 
Este aplicativo vem instalado por padrão e pode ser acessado na aba Ferramentas. 
 
Após a abertura, ele apresenta uma interface gráfica com 3 abas na parte superior. São elas: 
 
Sistemas Operacionais 
Marcio Quirino - 105 
 
Local onde são exibidas as informações de cada um dos processos. 
 
Janela que mostra, em forma de gráfic, o uso de cada recurso do sistema. 
 
Considerações finais 
Ao longo deste tema, fizemos uma viagem pelos conceitos relacionados ao gerenciamento de 
memória pelos sistemas operacionais. 
No primeiro módulo, vimos como os processos enxergam a memória e os princípios básicos da 
gerência pelo SO, incluindo proteção e relocação. No segundo módulo, vimos as principais políticas de 
alocação de memória, desde a mais simples em sistemas monotarefa até as mais complexas, com troca de 
processo entre o disco e a memória. 
Em seguida, estudamos a memória virtual, como ela é implementada utilizando a paginação sob 
demanda e a diferença entre segmentação e paginação. Finalmente, no último módulo, estudamos um SO 
real, o Linux, que realiza o gerenciamento de sua memória. 
Referências 
OFFICIAL UBUNTU DOCUMENTATION. Consultado em meio eletrônico em: 10 dez. 2020. 
SILBERSCHATZ, A. Fundamentos de sistemas operacionais. 9. ed. Rio de Janeiro: LTC, 2015. 
SILVA, G. M. Guia Foca GNU/Linux. Consultado em meio eletrônico em: 10 dez. 2020. 
TANENBAUM, A. S. Organização estruturada de computadores. 5. ed. São Paulo: Pearson, 2006. 
TANENBAUM, A. S.; BOS, H. Sistemas operacionais modernos. 4. ed. São Paulo: Pearson 
Educacional do Brasil, 2016. 
TANENBAUM, A. S.; WOODHULL, A. S. Sistemas operacionais: projeto e Implementação. 3. ed. 
Porto Alegre: Bookman, 2008. 
EXPLORE+ 
Para saber mais sobre os assuntos tratados neste tema, acesse o site: 
Training, do professor Luiz Paulo Maia. 
Sistemas Operacionais 
Marcio Quirino - 106 
 
Sistema de Arquivos 
 
Descrição 
Tecnologias para particionamento e formatação de sistemas de arquivos e sua implementação e 
gerenciamento no sistema operacional Linux. 
Propósito 
Compreender a importância da implementação e o gerenciamento de sistemas de arquivos pelos 
principais sistemas operacionais do mercado, objetivando determinar o melhor sistema para cada situação, 
assim como realizar sua gerência de forma eficaz. 
Preparação 
Antes de iniciar o estudo do tema, é desejável ter acesso a um computador (ou máquina virtual) com 
Linux instalado. Para os exemplos, foi utilizado o Ubuntu Desktop 20.04 LTS. 
Introdução 
Os sistemas operacionais são softwares essenciais para quaisquer dispositivos computacionais. Eles 
permitem que haja maior facilidade de uso por parte dos usuários, disponibilizando interfaces amigáveis 
assim como recursos para que as tarefas dos desenvolvedores sejam menos árduas. 
Uma das tarefas que são desempenhadas pelos sistemas operacionais é fornecer um sistema que 
garanta a persistência das informações tratadas, armazenando-as nos dispositivos intermediários, como os 
discos rígidos magnéticos. Essas tarefas são implementadas pelos sistemas de arquivos. 
Para compreender tal funcionalidade, estudaremos os conceitos de sistemas de arquivos e as 
diferentes formas de implementação, com ênfase nas vantagens e desvantagens de cada uma. Para isso, 
veremos as técnicas de formatação que foram desenvolvidas e conheceremos como se dá a implementação 
do sistema de arquivos do Linux. 
De forma a solidificar esse conhecimento, aprenderemos sobre discos e partições, e como estas 
últimas são criadas em um sistema Linux. Veremos ainda como fazer a formação e a montagem dos 
sistemas de arquivos. 
Uma vez criado tal sistema, vamos estudar as principais ferramentas que um administrador deve 
conhecer para manter o funcionamento. Por fim, conheceremos os principais editores de arquivos que 
podem ser utilizados para a configuração e a manutenção de um sistema Linux. 
1. Como são implementados os sistemas de arquivos 
Conceitos 
Quando estamos utilizando um sistema computacional, é comum que, ao encerrar nossas atividades, 
guardemos o trabalho realizado para continuarmos em um momento posterior. Portanto, o armazenamento 
e a recuperação de informações são atividades essenciais para aplicações. 
As principais exigências para armazenamento de informações são: 
• Deve ser possível armazenar uma grande quantidade de informações. 
• A informação deve sobreviver à finalização do processo que a utiliza (deve ser persistente). 
Sistemas Operacionais 
Marcio Quirino - 107 
 
• Múltiplos processos devem ser capazes de acessar as informações concorrentemente. 
É mediante a implementação de arquivos em discos ou outras mídias que o sistema operacional 
estrutura e organiza essas informações. 
Você sabia 
A parte responsável por essa gerência é denominada sistema de arquivos. 
A manipulação de arquivos deve ocorrer de maneira uniforme, independente dos diferentes 
dispositivos de armazenamento. 
De uma forma simplista, bastaria pensar em um dispositivo de armazenamento como uma sequência 
linear de blocos de tamanho fixo que dão suporte a duas operações: 
• Ler o bloco k; 
• Escrever no bloco k. 
No entanto, essas são operações inconvenientes quando utilizadas em sistemas com muitas 
aplicações e possivelmente múltiplos usuários. 
Algumas questões que surgem são: 
• Como saber em qual bloco se encontram as informações que necessitamos? 
• Como impedir que um usuário leia os dados de outro usuário? 
• Como saber quais blocos estão livres? 
O sistema de arquivos é constituído de duas partes distintas: 
A. Conjunto de arquivos 
Armazena dados. 
B. Estrutura de diretórios 
Organiza e fornece informações sobre os arquivos do sistema. 
Arquivos são unidades lógicas de informação criadas por processos. Um disco normalmente conterá 
milhares ou mesmo milhões deles, cada um independente dos outros. 
Processos 
É um programa em execução em um sistema operacional, incluindo seu contexto de hardware (estado do 
hardware em determinado momento), valores de variáveis e seu espaço de endereçamento (região de memória que o 
processo pode utilizar). 
Arquivos 
Computadores podem armazenar dados em diferentes dispositivos de armazenamento, porém o 
usuário precisa acessar os dados contidos nestes dispositivos da mesma forma, independente do seu tipo. 
Resumindo 
Para que um sistema possa ser usado de forma conveniente, o sistema operacional deve oferecer uma visão 
lógica e uniforme do dispositivo de armazenamento. 
Um arquivo é constituído de informações, podendo representar programas ou dados. Um programa 
contém instruções compreendidas pela UCP (arquivo executável), enquanto um arquivo de dados pode ser 
estruturado livremente (podem ser numéricos, alfabéticos, alfanuméricos ou binários). 
Sistemas Operacionais 
Marcio Quirino - 108 
 
Um arquivo é identificado por intermédio de um nome, e as regras para os nomes variam de sistema 
para sistema. 
Saiba mais 
Em alguns sistemas operacionais, o nome do arquivo é composto por duas partes separadas com um ponto. 
A parte após o ponto é denominada extensão do arquivo e tem como finalidade identificar seu conteúdo. 
As principais diferenças entre as regras para os nomes de arquivo são: 
• Quantidade máxima de caracteres; 
• Diferenciação entre caracteres maiúsculos e minúsculos; 
• Uso de caracteres especiais; 
• Nomes com extensão tendo significado ou não. 
Em alguns sistemas, as extensões de arquivos são apenas convenções e não são impostas pelo 
sistema operacional. 
Exemplo 
Um arquivo chamado “file.txt” pode ser algum tipo de arquivo de texto, mas aquele nome tem mais função de 
lembrar o proprietário do que transmitir qualquer informação real para o computador. Por outro lado, um compilador de 
Linguagem C pode exigir queos arquivos que ele tem de compilar terminem em “.c”. O sistema operacional, no entanto, 
não se importa. 
Ao criar um arquivo, o processo deve atribuir um nome a ele para que, quando termine sua execução, 
o arquivo continue existindo e possa ser acessado por outros processos pelo mesmo nome. Ao receber um 
nome, o arquivo se torna independente do processo, do usuário e até mesmo do sistema que o criou. 
Estrutura de Arquivos 
No momento da criação de um arquivo, é possível definir qual organização será adotada. Esta 
organização pode ser uma estrutura suportada pelo sistema operacional ou definida pela própria aplicação. 
Clique nas barras para ver as informações. 
A. Sequência desestruturada de bytes 
É a forma mais simples de organização de arquivos. Nesse tipo de organização, o sistema de 
arquivos não impõe nenhuma estrutura lógica para os dados (a aplicação deve definir toda a 
organização). A grande vantagem é a flexibilidade para criar diferentes estruturas de dados, mas 
todo o controle de acesso ao arquivo é de inteira responsabilidade da aplicação. Qualquer 
significado deve ser imposto por programas em nível de usuário. Tanto o Linux quanto o MS 
Windows usam essa abordagem. 
B. Sequência de registros de tamanho fixo 
É uma forma estruturada para o armazenamento de arquivos. Nela o arquivo é composto por 
uma série de registros com uma estrutura interna característica, e as operações de 
leitura/gravação trabalham com registros inteiros. No passado, quando o cartão de 80 colunas 
perfurado era utilizado, muitos sistemas operacionais de computadores de grande porte 
baseavam seus sistemas de arquivos em arquivos consistindo em registros de 80 caracteres. 
Esses sistemas também aceitavam arquivos com registros de 132 caracteres, destinados às 
impressoras de linha. Nenhum sistema de propósito geral atual utiliza esse modelo como seu 
sistema primário de arquivos. 
C. Árvore de registros 
Sistemas Operacionais 
Marcio Quirino - 109 
 
Uma organização que é composta por registros que não possuem necessariamente o mesmo 
tamanho, e cada um contém um campo com uma chave em uma posição fixa. A árvore é 
ordenada pelo campo chave de forma a permitir uma busca rápida. Esse tipo de arquivo é 
bastante diferente das sequências de bytes desestruturadas, sendo utilizado em alguns 
computadores de grande porte para o processamento de dados comerciais. 
 
Métodos de Acesso 
Os primeiros sistemas operacionais acessavam os registros de um arquivo na ordem em que eram 
gravados, possibilitando a gravação de novos registros apenas no final. A esse tipo de acesso dá-se o nome 
de acesso sequencial. 
Atenção 
É possível retroceder registros, mas nunca pular ou lê-los fora de ordem. 
Posteriormente, surgiu um método de acesso mais eficientes, o acesso aleatório (também conhecido 
como acesso direto), que permite a leitura/gravação de um registro diretamente na sua posição relativa ao 
início do arquivo. O acesso aleatório somente é possível quando o arquivo é definido com registros de 
tamanho fixo. Neste acesso, não existe restrição à ordem em que os registros são lidos ou gravados. 
• Em sistemas operacionais antigos, o tipo de acesso ao arquivo é determinado quando o 
arquivo é criado. 
• Nos sistemas operacionais modernos, todos os arquivos são de acesso aleatório, 
excetuando-se os casos em que o dispositivo no qual o arquivo está armazenado não permita 
esse tipo de acesso. 
Existem ainda outros métodos de acesso menos comuns, como o acesso indexado, que envolve a 
construção de um índice para o arquivo. Esse índice contém ponteiros para os blocos e, para acessar uma 
posição de arquivo, primeiro pesquisa-se o índice e depois utiliza-se o ponteiro para a posição desejada. 
Tipos de Arquivos 
Os sistemas operacionais costumam suportar vários tipos de arquivos, sendo os mais comuns: 
A. Arquivos regulares 
Arquivos que contém informações genéricas como, por exemplo, dados dos usuários. 
B. Diretórios 
Arquivos de sistema usados para manter a estrutura do sistema de arquivos. 
C. Arquivos especiais de caractere 
Sistemas Operacionais 
Marcio Quirino - 110 
 
Relacionam-se com operações de E/S e costumam modelar dispositivos seriais. 
D. Arquivos especiais de bloco 
Usados para modelar dispositivos de bloco, em especial discos. 
Em geral, arquivos regulares são classificados como arquivo texto ou arquivo binário. 
A. Arquivo texto 
Um arquivo texto (ou arquivo ASCII) é constituído por linhas de texto que podem ter tamanhos 
diferentes e terminam por caracteres especiais para indicar o fim da linha. São arquivos que, 
quando exibidos na tela ou impressos, podem ser compreendidos pelas pessoas e, ainda, 
editados com um editor de textos comum. 
B. Arquivo binário 
Arquivos binários não são arquivos texto. Sua listagem gera um conjunto de caracteres 
incompreensíveis. Eles podem ser arquivos de usuários (com ou sem estrutura interna) ou 
arquivos executáveis (com estrutura conhecida pelo sistema operacional e códigos que são 
executados pela UCP). 
Diretórios 
A estrutura de diretórios é o modo como o sistema organiza logicamente os diversos arquivos 
contidos em um disco. O diretório (ou pasta) é um arquivo que contém uma estrutura de dados com entradas 
associadas aos arquivos onde são armazenadas informações como localização física, nome, organização e 
demais atributos. 
Quando é solicitada a abertura de um arquivo, o sistema operacional pesquisa o diretório até 
encontrar uma entrada com o nome do arquivo. Quando a entrada é localizada, o sistema operacional copia 
os atributos e os endereços de disco e os coloca em uma estrutura na memória, a tabela de arquivos, que 
contém todos os arquivos abertos. Quando o arquivo é fechado, sua entrada na tabela de arquivos é 
liberada. 
A implementação mais simples de uma estrutura de diretórios é chamada de nível único (um nível), 
no qual existe um único diretório contendo todos os arquivos do disco. Este modelo é bastante limitado, já 
que não permite que usuários criem arquivos com o mesmo nome, o que ocasionaria um conflito no acesso 
a eles. 
Comentário 
Este tipo de implementação não é mais utilizado atualmente. 
Em outra estrutura, conhecida como diretório de dois níveis, existe um diretório para os arquivos do 
sistema e um diretório para cada usuário. Com esta implementação, cada usuário pode criar arquivos sem 
a preocupação de conhecer os demais arquivos do disco. Para que o sistema possa localizar arquivos nesta 
estrutura, existe um nível de diretório adicional denominado master file directory, indexado pelo nome do 
usuário. Nele, cada entrada aponta para o diretório de cada usuário. 
Atenção 
Para referenciar um arquivo neste tipo de estrutura, é necessário especificar o diretório onde ele se encontra 
e o seu nome, especificando assim seu caminho (path). 
A organização dos arquivos em um único diretório não permite uma organização adequada. A 
extensão para um modelo de múltiplos níveis permite que os arquivos sejam mais bem organizados. Este 
modelo, chamado estrutura de diretórios em árvore ou sistema de diretórios hierárquico, é atualmente 
adotado pela maioria dos sistemas operacionais. 
Sistemas Operacionais 
Marcio Quirino - 111 
 
Na estrutura em árvore, é possível criar quantos diretórios se deseje, podendo um diretório conter 
arquivos ou outros diretórios (subdiretórios). Cada arquivo, nesta estrutura, possui um caminho (path) único 
que descreve todos os diretórios desde a raiz até o diretório no qual o arquivo está, mais o nome do arquivo. 
Quando o sistema de arquivos é organizado como uma árvore de diretórios, os nomes de caminhos 
podem ser absolutos ou relativos. 
A. Caminho absoluto 
Consiste no caminho desde o diretório raiz (diretório inicial do sistema de arquivos) até o arquivo. 
B. Caminho relativo 
É utilizado em conjunto com o conceito de diretório de trabalho (diretório atual), que é o diretório 
usadoatualmente pelo processo e serve como base caso o nome do caminho não inicie com o 
diretório raiz. Quando é utilizado um caminho relativo, o caminho até o arquivo é buscado a partir 
do diretório de trabalho. 
Cada processo possui seu próprio diretório de trabalho. Assim, se algum processo alterar seu 
diretório de trabalho, os outros processos do usuário não serão afetados. 
A maioria dos sistemas que suporta estrutura de diretórios em árvore tem duas entradas especiais 
para cada diretório: 
• “.” → Diretório atual; 
• “..” → Diretório pai. Pode ser usada para subir na árvore de diretórios. 
Implementação do sistema de arquivos 
Os discos são o meio de armazenamento secundário mais comum no qual os arquivos são 
armazenados. As transferências de dados entre a memória e o disco são realizadas em unidades chamadas 
blocos, cada qual constituída por um ou mais setores. 
Exemplo 
Dependendo do disco, um setor pode variar de 32 a 4096 bytes, sendo mais comum setores de 512 bytes. 
A maioria dos discos pode ser dividida em uma ou mais partições, com sistemas de arquivos 
independentes em cada partição. O Setor 0 do disco é chamado de MBR (Master Boot Record — registro 
mestre de inicialização) e é usado para inicializar o computador. No final do MBR está localizada a tabela 
de partição, que armazena os endereços de início e fim de cada partição. Uma das partições da tabela é 
marcada como ativa. 
Quando o computador é inicializado, a BIOS lê e executa o MBR. A primeira coisa que o programa 
MBR faz é localizar a partição ativa, ler seu primeiro bloco (bloco de inicialização) e executá-lo. O programa 
no bloco de inicialização carrega o sistema operacional contido naquela partição. Cada partição começa 
com um bloco de inicialização, mesmo que ela não contenha um sistema operacional que possa ser 
inicializado. 
BIOS 
BIOS (Basic Input/Output System - Sistema Básico de Entrada/Saída) é um pequeno programa gravado em 
uma memória não volátil usado para realizar a inicialização do hardware durante o processo de inicialização de um 
computador e para fornecer serviços de tempo de execução para sistemas operacionais e programas. 
Atenção 
O esquema de uma partição de disco varia bastante entre sistemas de arquivos. 
Sistemas Operacionais 
Marcio Quirino - 112 
 
O primeiro item em uma partição costuma ser o superbloco. Ele contém todos os parâmetros chave 
a respeito do sistema de arquivos e é lido para a memória quando o computador é inicializado ou o sistema 
de arquivos é tocado pela primeira vez. Informações típicas no superbloco incluem um identificador para o 
tipo de sistema de arquivos, sua quantidade de blocos e outras informações administrativas. 
Podem vir informações a respeito de blocos disponíveis no sistema de arquivos, na forma de um 
mapa de bits ou de uma lista encadeada. 
Pode ser seguido pelos i-nodes (um arranjo de estruturas de dados, um por arquivo, dizendo tudo 
sobre ele). Depois pode vir o diretório-raiz, que contém o topo da árvore do sistema de arquivos. Por fim, o 
restante do disco contém todos os outros diretórios e arquivos. 
A criação de arquivos em disco exige que o sistema operacional tenha o controle de quais blocos no 
disco estão livres. Este controle é realizado através de uma estrutura de dados que armazena informações 
que possibilitam ao sistema de arquivos gerenciar o disco. 
Dica 
A forma mais simples de implementar uma estrutura de espaços livres é através de uma tabela denominada 
mapa de bits. A cada entrada da tabela é associada um bloco do disco representado por um bit, que pode assumir 
valor igual a 0 (bloco livre) ou 1 (bloco alocado). 
Uma segunda maneira de realizar este controle é por meio de uma lista encadeada de todos os 
blocos livres do disco. Cada bloco possui uma área reservada para armazenamento do endereço do próximo 
bloco, e a partir do primeiro bloco livre pode-se ter acesso aos demais de forma encadeada. Suas principais 
restrições são o espaço utilizado no bloco com informação de controle e o fato do algoritmo de busca de 
espaço livre sempre ter que realizar uma pesquisa sequencial na lista. 
Outra solução leva em conta que blocos contíguos são geralmente alocados ou liberados 
simultaneamente, enxergando o disco como um conjunto de segmentos de blocos livres. Assim, é possível 
manter uma tabela de blocos livres com o endereço do primeiro bloco de cada segmento e o número de 
blocos livres contíguos que se seguem. 
 
Alocação Contígua 
A alocação contígua consiste em armazenar um arquivo em blocos contíguos de dados no disco. 
Neste tipo de alocação, o sistema localiza um arquivo através do endereço do primeiro bloco e da sua 
quantidade de blocos. 
A alocação de espaço de disco contíguo tem duas vantagens. 
A. Primeira vantagem 
Ela é simples de implementar. Dado o número do primeiro bloco, o número de qualquer outro 
bloco pode ser encontrado mediante uma simples adição. 
Sistemas Operacionais 
Marcio Quirino - 113 
 
 
B. Segunda vantagem 
O desempenho da leitura é excelente, pois o arquivo inteiro pode ser lido do disco em uma única 
operação. 
O acesso a arquivos dispostos contiguamente no disco é bastante simples tanto para o acesso 
sequencial quanto para o acesso aleatório. Seu principal problema é a alocação de espaço livre para novos 
arquivos, já que para um arquivo ser criado com n blocos é necessário que exista uma cadeia de n blocos 
dispostos sequencialmente no disco. 
O disco pode ser visto como um grande vetor no qual os elementos podem ser considerados 
segmentos com tamanhos diferentes de blocos contíguos, dispostos alternadamente entre segmentos 
ocupados e segmentos livres. No momento em que o sistema operacional deseja alocar espaço para 
armazenar um novo arquivo, pode existir mais de um segmento livre disponível com o tamanho exigido. 
Atenção 
Neste caso, é necessário que alguma estratégia de alocação seja adotada para selecionar qual o segmento na 
lista de blocos livres deve ser escolhido. 
Seja qual for a estratégia adotada, se o bloco livre selecionado para o armazenamento do arquivo 
for maior que o tamanho do arquivo, sobrará um espaço livre ao final do bloco. Com a operação em longo 
prazo, surgirão vários blocos livres espalhados pelo disco, ocorrendo a chamada fragmentação do disco. 
Quando o disco estiver muito fragmentado para que se possa alocar espaço para a criação do 
arquivo, será necessário realizar a desfragmentação do disco, que consiste em mover os arquivos para abrir 
espaço suficiente para o novo arquivo. 
Dica 
A desfragmentação é um processo demorado que deve ser realizado periodicamente. 
Atualmente, a alocação contígua é usada em CD-ROMs. Todos os tamanhos de arquivos são 
conhecidos antecipadamente e jamais mudarão durante o uso subsequente do sistema de arquivos do CD-
ROM. 
Alocação por Lista Encadeada 
Na alocação por lista encadeada, um arquivo é organizado como um conjunto de blocos ligados 
logicamente, independente da sua localização física. Cada bloco deve possuir um ponteiro para o bloco 
seguinte e assim por diante. 
Atenção 
A entrada de diretório precisa armazenar somente o endereço do primeiro bloco. 
A fragmentação do disco não ocorre na alocação encadeada já que os blocos alocados para 
determinado arquivo não precisam estar em posições contíguas. O que ocorre, neste método, é 
a fragmentação de arquivos, que é a quebra do arquivo em diversos blocos espalhados pelo disco. Tal 
fragmentação resulta no aumento do tempo de acesso, pois o processo de leitura/gravação provoca muitos 
deslocamentos da cabeça de leitura/gravação do disco. 
Dica 
Para otimizar o tempo das operações de E/S é importante que o sistema de arquivos seja desfragmentado 
periodicamente. 
Sistemas Operacionais 
Marcio Quirino - 114 
 
 
A alocação por lista encadeada permite apenas o acesso sequencial aos blocos de um arquivo. Isso 
constitui uma das principais desvantagens dessatécnica. Além disso, é desperdiçado espaço nos blocos 
com o armazenamento de ponteiros. 
Outro problema da alocação por lista encadeada é a confiabilidade. Se o valor de um ponteiro é 
corrompido, se perde o encadeamento do arquivo. 
Alocação por Lista Encadeada Utilizando Índice 
É um esquema de alocação muito parecido com a alocação por lista encadeada, mas no lugar de 
fazer o encadeamento utilizando um ponteiro no bloco, o encadeamento é mantido em uma tabela. 
Embora a cadeia ainda precise ser seguida para o acesso aleatório, ela é seguida por intermédio da 
tabela e não consultando bloco a bloco. Se a tabela for mantida em memória, o acesso torna-se bem mais 
rápido. 
Essa tabela na memória principal é chamada de FAT (File Allocation Table — tabela de alocação de 
arquivos). Usando essa organização, todo o bloco do disco fica disponível para os dados do arquivo. 
Da mesma maneira que no método anterior, é suficiente para a entrada de diretório manter um único 
inteiro (o número do bloco inicial) e ainda assim ser capaz de localizar todos os blocos, não importando o 
tamanho do arquivo. 
A principal desvantagem é que a tabela pode ser muito grande para discos grandes. Esse problema 
pode ser minimizado agrupando os blocos em clusters para formar unidades maiores, mas isto provoca um 
maior desperdício por causa da parte não utilizada do último cluster, que tenderá a ser maior. 
Clusters 
Agrupamentos de blocos de um disco. 
 
 
I-nodes (Alocação Indexada) 
O método consiste em associar a cada arquivo uma tabela denominada i-node (nó-índice ou nó-i), 
que lista os atributos e os endereços em disco dos blocos do arquivo. 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 115 
 
 
A grande vantagem desse esquema sobre a alocação por lista encadeada utilizando índice é que o 
i-node precisa estar na memória apenas quando o arquivo correspondente estiver aberto. 
Se cada i-node ocupar n bytes e k arquivos estiverem abertos simultaneamente, a memória total 
ocupada pelo arranjo contendo os i-nodes para os arquivos abertos é de apenas k × n bytes. 
Esse arranjo é, em geral, muito menor do que o espaço ocupado pela tabela de arquivos na alocação 
por lista encadeada utilizando índice. 
Os primeiros endereços de disco são armazenados no próprio i-node. Isto significa que para arquivos 
pequenos toda a informação está contida no próprio i-node e pode ser transferida para a memória quando 
o arquivo é aberto. 
A. Bloco indireto simples 
Contém endereços de blocos adicionais para o arquivo. É usado para arquivos maiores. 
B. Bloco indireto duplo 
Contém o endereço do bloco que possui uma lista de blocos indiretos simples relativos ao arquivo. 
C. Bloco indireto triplo 
Contém o endereço do bloco que possui uma lista de blocos indiretos duplos. 
 
IMPLEMENTAÇÃO DE CACHE 
O acesso a disco é lento quando comparado com o acesso à memória principal. Este é o fator básico 
para as operações de E/S com discos serem um problema para o desempenho do sistema. Com o objetivo 
de minimizar tal problema, a maioria dos sistemas de arquivos implementa uma técnica denominada cache. 
Sistemas Operacionais 
Marcio Quirino - 116 
 
Neste esquema, o sistema operacional reserva uma área na memória principal para que se tornem 
disponíveis caches utilizados em operações de acesso ao disco. 
Quando uma operação de E/S é realizada, o sistema verifica se a informação desejada se encontra 
na cache. Caso esteja disponível, não é necessário acesso ao disco. Caso o bloco requisitado não se 
encontre na cache, a operação de E/S é realizada e a cache é atualizada. Como existe uma limitação no 
tamanho da cache, o sistema deve adotar uma política para substituição de blocos. 
Apesar de melhorar o desempenho do sistema, aspectos de segurança devem ser levados em 
consideração. No caso de blocos de dados permanecerem por muito tempo na cache, a ocorrência de 
problemas de energia pode ocasionar a perda de tarefas já realizadas e consideradas salvas em disco. 
Existem duas maneiras de tratar este problema. 
• No primeiro caso, o sistema operacional possui uma rotina que executa periodicamente 
atualizando em disco todos os blocos modificados da cache. 
• Uma segunda alternativa, conhecida como write-through, é realizar imediatamente uma 
atualização no disco sempre que um bloco da cache for modificado. 
Quando a memória cache não atualiza o disco imediatamente, temos a chamada cache write-back. 
A técnica write-back implica em menor quantidade de operações de E/S, porém o risco de perda de dados 
é maior. Isso não acontece nas caches write-through em função do seu próprio funcionamento, mas o 
aumento considerável nas operações de E/S torna este método menos eficiente. 
2. Conceitos de sistemas de arquivos 
O sistema de arquivos do Linux 
O Linux trata o conceito de arquivo de uma forma bastante ampla. Um arquivo não precisa ser um 
objeto em um disco, mas pode ser qualquer objeto capaz de manipular dados. O Linux manipula todos esses 
objetos ocultando detalhes específicos de cada implementação por intermédio de uma camada de software 
denominada sistema de arquivos virtual (Virtual File System – VFS). 
O VFS define quatro tipos de objetos principais: 
A. I-Node 
Representa um arquivo individual. 
B. Arquivo 
Representa um arquivo aberto. 
C. Superbloco 
Representa um sistema de arquivos inteiro. 
D. Dentry 
Representa uma entrada de diretório individual. 
Para cada um desses objetos, o VFS define um conjunto de chamadas de sistema, e cada objeto 
possui um ponteiro para uma tabela de funções que lista as funções reais que implementam as chamadas 
de sistema dos objetos. O VFS pode executar uma operação sobre um dos objetos do sistema de arquivos, 
chamando a função apropriada na tabela de funções sem precisar saber de antemão com que tipo de objeto 
está lidando. 
Sistemas Operacionais 
Marcio Quirino - 117 
 
Os objetos arquivo pertencem a um único processo, mas os objetos i-node não. Há um 
objeto arquivo para cada instância de um arquivo aberto, mas um único objeto i-node. 
Atenção 
Mesmo quando um arquivo não está sendo mais utilizado por algum processo, seu objeto i-node ainda pode 
ser armazenado em cache pelo VFS. 
Arquivos de diretório são manipulados de forma diferente de outros arquivos. O Linux define as 
chamadas de sistema para diretórios (criação, exclusão, renomeação de arquivo etc.) no objeto i-node, no 
lugar do objeto arquivo. 
O Linux mantém um único objeto superbloco para cada dispositivo de disco montado e para cada 
sistema de arquivos de rede conectado. A principal função do objeto superbloco é dar acesso a i-nodes. 
Um objeto dentry representa uma entrada de diretório que pode ser o nome de um diretório no nome 
de caminho de um arquivo. 
Exemplo 
arquivo “/home/maria/teste.txt” possui as entradas de diretório “/”, “home”, “maria” e “teste.txt”, sendo cada uma 
destas entradas representada por um objeto dentry diferente. 
MINIX 
Sistema Operacional Unix-like escrito por Andrew S. Tanenbaum e utilizado por Linus Torvalds como base para 
o desenvolvimento do Linux. 
A primeira versão do Linux implementava o sistema de arquivos do MINIX, que limitava os nomes de 
arquivos a 14 caracteres e tinha um limite de 64 MB para o tamanho máximo que eles poderiam ter. 
Desde o início, havia o interesse em desenvolver um sistema de arquivos mais satisfatório, que foi 
implementado com o sistema de arquivos ext, o qual permitia arquivos com até 2 GB de dados e com nomes 
de até 255 caracteres. Seu problema consistia em ser mais lento que o sistema de arquivos do MINIX. 
Você sabia 
A versão 2 do ext, conhecida como ext2, resolveu os problemas de desempenho do ext, permitindo nomes 
longos e tornando o principal sistema de arquivos do Linux. 
Devido à implementação do VFS, o Linux suporta dezenas de sistemas de arquivos diferentes. 
Quando o sistema é iniciado, o conjunto de funções para oacesso ao sistema de arquivos principal deve 
estar compilado no núcleo do Linux para que possa ser montado e utilizado. Durante a execução, módulos 
para acesso a outros sistemas de arquivos podem ser carregados dinamicamente, permitindo, assim, a 
utilização simultânea de diferentes sistemas de arquivos. 
O Linux não exige que arquivos possuam extensões (caracteres após um caractere “.”), nem limita o 
tipo ou a quantidade de caracteres presentes em uma extensão. Ainda, arquivos podem ter qualquer 
quantidade de extensões (o que é comum). No entanto, vários programas esperam que arquivos possuam 
extensões. 
Está a cargo dos programas interpretar ou não o tipo do arquivo por sua extensão, visto que para o 
Linux a extensão de um arquivo não possui nenhum significado. 
O diretório raiz é chamado /, que além de ser utilizado para separar nomes de diretórios, é um 
caractere que contém subdiretórios. Sob o diretório raiz, existe um grupo de diretórios comuns à maioria das 
distribuições Linux. Alguns dos que estão localizados diretamente no diretório raiz, são: 
• /bin → Arquivos executáveis; 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 118 
 
• /boot → Arquivos de configuração do boot, kernel e outros arquivos necessários para a 
inicialização do sistema; 
• /dev → Contém os dispositivos do sistema; 
• /etc → Arquivos de configuração, scripts de inicialização etc; 
• /home → Diretórios home para usuários do sistema; 
• /lib → Bibliotecas e módulos do sistema; 
• /lib64 → Semelhante ao /lib, mas contém arquivos específicos do sistema 64 bits; 
• /media → Onde são montados dispositivos externos; 
• /mnt → Local para montagem manual de dispositivos. Normalmente utilizado para montagens 
provisórias; 
• /opt → Fornece um local opcional para aplicações serem instaladas. Normalmente utilizado para 
instalação de aplicativos que não fazem parte do sistema; 
• /proc → Diretório dinâmico especial que mantém informação sobre o estado do sistema, incluindo 
os processos em execução. Contém algumas variáveis do kernel que podem, inclusive, ser 
modificadas; 
• /root → Diretório home do usuário root (administrador do sistema); 
• /sbin → Arquivos executáveis para administração do sistema; 
• /srv → Contém arquivos de alguns serviços do sistema. Por exemplo, servidor web; 
• /sys → Semelhante ao /proc. Contém arquivos especiais do kernel; 
• /tmp → Contém arquivos temporários; 
• /usr → Aplicativos e arquivos que são, na maioria das vezes, disponíveis para acesso por todos 
os usuários; 
• /var → Arquivos de logs e bancos de dados. 
ext2 
O ext2 foi um dos sistemas de arquivos mais populares desenvolvido para o Linux. O layout de uma 
partição ext2 é mostrado na figura a seguir: 
Layout de uma partição ext2. 
O primeiro bloco (bloco de inicialização) não é utilizado pela partição, é reservado para a inicialização 
do computador. Após o primeiro bloco seguem grupos de blocos de mesma organização. 
O superbloco contém informações sobre o layout do sistema de arquivos, como a quantidade de i-
nodes e a quantidade de blocos de disco. O descritor do grupo contém informações sobre a localização 
dos mapas de bits, a quantidade de blocos livres e i-nodes no grupo, e a quantidade de diretórios no grupo. 
Dois mapas de bits são usados para controlar os blocos livres e i-nodes livres. Cada mapa contém um bloco 
de comprimento. Em seguida, estão os i-nodes, os quais são numerados de 1 até algum máximo. Cada i-
node tem 128 bytes de comprimento e descreve exatamente um arquivo. 
 
Sistemas Operacionais 
Marcio Quirino - 119 
 
Atenção 
Um i-node contém informações de contabilidade e dados suficientes para localizar todos os blocos de disco 
que contêm os dados do arquivo. 
Por fim, estão os blocos de dados, onde os arquivos e diretórios estão armazenados. 
Os diretórios ficam dispersos pelos grupos de blocos do disco. O ext2 procura colocar arquivos de 
dados no mesmo grupo de blocos que o i-node do arquivo original. Os mapas de bits são usados para tomar 
decisões rápidas sobre onde alocar novos dados do sistema de arquivos. Quando novos blocos de arquivos 
são alocados, o ext2 pré-aloca 8 blocos adicionais de maneira a minimizar a fragmentação de arquivos por 
futuras operações de escrita. Essa pré-alocação equilibra a carga do sistema de arquivos. 
Um diretório armazena nomes de arquivos, sendo ilustrado na figura a seguir, onde existem entradas 
para 2 arquivos (projeto e documento.txt) e um diretório (dados). 
Diretório do ext2. 
Dentro de um diretório, as entradas para arquivos e diretórios estão fora de ordem. Pode acontecer 
de uma entrada não ocupar blocos de disco inteiros, então é comum haver bytes não utilizados no final de 
cada bloco de disco. 
Cada entrada de diretório consiste em 4 campos de comprimento fixo e 1 campo de comprimento 
variável. 
A. Primeiro campo 
O primeiro campo é o número do i-node (16 para projeto, 22 para documento.txt e 91 para dados). 
B. Segundo campo 
O segundo campo contém o tamanho da entrada, incluindo espaços não utilizados no seu final. 
C. Terceiro campo 
O terceiro campo identifica o tipo (arquivo, diretório, link etc.). 
D. Quarto campo 
O quarto campo é o tamanho do nome do arquivo. 
E. Quinto campo 
O quinto campo possui tamanho variável e armazena o nome do arquivo. 
Sistemas Operacionais 
Marcio Quirino - 120 
 
 
Formato do i-node. 
Hardlinks 
Hardlinks são diferentes entradas de diretórios que apontam para o mesmo i-node (o mesmo arquivo). 
Cada i-node do ext2 possui o formato ilustrado acima, em que: 
• Permissões → Permissões de acesso ao arquivo; 
• Contador de links → Quantidade de hardlinks que o arquivo possui; 
• UID → Dono do arquivo; 
• GID → Grupo do dono do arquivo. 
Journaling 
Para evitar perda de dados após problemas, como falta de energia, é necessário escrever blocos de 
dados no disco tão logo o bloco seja criado ou alterado, levando a um baixo desempenho do sistema devido 
à necessidade de movimentação das cabeças de leitura/gravação dos discos. 
Saiba mais 
Para minimizar tal problema, foi desenvolvido um recurso conhecido como journaling, no qual as alterações 
são gravadas sequencialmente em um diário em vez de serem escritas diretamente nos blocos de disco. 
Um conjunto de operações que executam uma tarefa específica é denominada transação. Quando 
uma transação é escrita no diário, ela é considerada confirmada e o sistema pode prosseguir. 
A seguir, as entradas do diário relacionadas com as transações são reexecutadas nas estruturas 
reais do sistema de arquivos. Quando uma transação é concluída (totalmente salva no disco), ela é removida 
do diário, que pode estar em uma seção separada do sistema de arquivos ou em um eixo separado do disco. 
Como fica em uma seção confinada do disco, é mais eficiente por diminuir os tempos de disputa e busca do 
cabeçote. 
Atenção 
Se o sistema cair e algumas transações permanecerem no diário, elas deverão ser concluídas quando o 
sistema se recuperar. 
O journaling foi implementado no Linux na terceira versão do ext, conhecida como ext3. 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 121 
 
Disco Rígido 
Um disco rígido é constituído por discos sobrepostos, unidos por um eixo vertical girando a uma 
velocidade constante. Cada disco é composto por trilhas concêntricas, que são divididas em setores. As 
trilhas dos diferentes discos que ocupam a mesma posição vertical formam um cilindro. Para cada superfície 
de um disco existe uma cabeça de leitura/gravação. O conjunto de cabeças é preso a um braço que se 
movimenta entre os vários cilindros no sentido radial. 
 
O tempo necessário para ler/gravar um bloco de dados é função de três fatores: tempo de busca, 
latência e transferência. 
• O tempo de busca (seek) é o tempo gasto para mover o braço até o cilindro onde o bloco se 
encontra. 
• O tempo de latência é o tempo de espera até que o setor desejadose posicione sob a 
cabeça de leitura/gravação. 
• O tempo de transferência corresponde ao tempo necessário para ler/gravar o bloco. 
 
Partições 
O particionamento de disco é uma divisão de seu espaço disponível em seções de forma que possam 
ser utilizadas de maneira independente. Uma partição pode ocupar um disco inteiro, ou podem ser criadas 
várias partições por disco, cada uma contendo um sistema de arquivos independente. 
As informações sobre as partições existentes em um disco são gravadas em uma tabela de partição 
no próprio disco. Para ser utilizada, uma partição deve ser formatada com um sistema de arquivos para que 
estes possam ser gravados nela. 
No Linux, os dispositivos são identificados por arquivos especiais que ficam armazenados no 
diretório /dev. A identificação de discos e partições é realizada de acordo com o seguinte padrão: 
Sistemas Operacionais 
Marcio Quirino - 122 
 
 
Algumas identificações de discos e partições em sistemas Linux: 
• /dev/fd0 → Primeira unidade de disquetes; 
• /dev/fd1 → Segunda unidade de disquetes; 
• /dev/sda → Primeiro disco rígido na primeira controladora SATA ou SCSI; 
• /dev/sda1 → Primeira partição do primeiro disco rígido SATA ou SCSI; 
• /dev/sda2 → Segunda partição do primeiro disco rígido SATA ou SCSI; 
• /dev/sdb → Segundo disco rígido na primeira controladora SATA ou SCSI; 
• /dev/sdb3 → Terceira partição do segundo disco rígido SATA ou SCSI; 
• /dev/sr0 → Primeiro CD-ROM SATA ou SCSI; 
• /dev/hda → Primeiro disco rígido na primeira controladora IDE; 
• /dev/hda1 → Primeira partição do primeiro disco rígido IDE. 
Gerenciamento de partições em Linux 
 Veremos agora como fazer o gerenciamento de partições em sistemas Linux. Para efeito de exercício, será 
utilizado o software de máquina virtual Oracle VirtualBox, que pode ser baixado gratuitamente do site 
https://www.virtualbox.org/. Para a criação deste documento, foi utilizada a versão 6.1 do VirtualBox. 
 As telas e comandos mostrados neste exemplo são relativos ao Ubuntu 20.04 LTS, instalado em uma máquina 
virtual no VirtualBox. 
Abra um terminal e procure por todas as entradas de dispositivos no diretório /dev que possua “sd” no nome 
utilizando o comando “ls -l /dev | grep sd”. 
fabio@ubuntu20:~$ ls -l /dev | grep sd 
brw-rw---- 1 root disk 8, 0 ago 28 16:44 sda brw-rw---- 1 root disk 8, 
1 ago 28 16:44 sda1 brw-rw---- 1 root disk 8, 2 ago 28 16:44 sda2 brw-rw---- 1 
root disk 8, 5 ago 28 16:44 sda5 
 Podemos ver pela saída do comando que existe o dispositivo /dev/sda e que ele possui 3 partições (/dev/sda1, 
/dev/sda2 e /dev/sda5). 
Vamos agora criar um segundo disco rígido virtual para este sistema operacional. Para isso, desligue e máquina 
virtual antes de prosseguir. 
Com a máquina virtual desligada, (1) selecione a máquina virtual no painel esquerdo do VirtualBox e (2) clique 
no botão Configurações. 
 
Sistemas Operacionais 
Marcio Quirino - 123 
 
 
Na janela de configurações da máquina virtual, (1) seleciona Armazenamento no painel esquerdo, (2) marque 
o controlador de disco rígido e (3) clique no botão para adicionar um novo disco rígido. 
 
 
Na tela seguinte, clique no botão Criar para criar um disco. Escolha o tipo de disco (VDI) e clique no botão 
Próximo, escolha como será a alocação (Dinamicamente alocado) e clique no botão Próximo, escolha um nome 
(utilizaremos o nome extra) e o tamanho do disco (utilizaremos 10 GB), e clique no botão Criar. 
 No seletor de discos (1) selecione o disco criado e (2) clique no botão Escolher. 
 
Sistemas Operacionais 
Marcio Quirino - 124 
 
 
 Deverá aparecer em sua máquina virtual o disco extra.vdi, conforme a imagem a seguir. 
 
 Confirme clicando no botão Ok e inicie sua máquina virtual. 
O resultado deste processo realizado na máquina virtual é o mesmo que acrescentar um novo disco rígido de 
10 GB a um computador real. 
Abra um terminal e procure novamente por todas as entradas de dispositivos no diretório /dev que possua “sd” 
no nome utilizando o comando “ls -l /dev | grep sd”. 
fabio@ubuntu20:~$ ls -l /dev | grep sd 
brw-rw---- 1 root disk 8, 0 ago 28 17:18 sda brw-rw---- 1 root disk 8, 1 ago 28 17:18 sda1 brw-rw-
--- 1 root disk 8, 2 ago 28 17:18 sda2 brw-rw---- 1 root disk 8, 5 ago 28 17:18 sda5 brw-rw---- 1 root disk 
8, 16 ago 28 17:18 sdb 
Podemos ver, pela saída do comando, que em comparação com a execução anterior, apareceu o dispositivo 
/dev/sdb (segundo disco rígido SATA). Como ainda não foram criadas partições para este disco rígido, não existem 
outras informações. 
 O primeiro passo para a utilização de um disco rígido recém instalado é a criação das partições para posterior 
instalação do sistema operacional. Os programas mais utilizados para o particionamento de discos são: 
fdisk → Programa padrão de sistema Unix para particionamento de discos. Interface em modo texto. 
cfdisk → Programa para operações básicas de particionamento de disco baseado na biblioteca ncurses, que 
fornece uma interface mais amigável, embora ainda em modo texto. 
Sistemas Operacionais 
Marcio Quirino - 125 
 
parted → Programa em modo texto que permite operações complexas sobre partições como, por exemplo, 
criação, eliminação, alteração de tamanho e movimentação. 
gparted → Interface gráfica que permite operações complexas sobre partições. Funciona emitindo comandos 
para o parted, que deve estar instalado no sistema. 
Veremos como criar as partições utilizando primeiro o fdisk, programa padrão para sistemas Linux. Depois 
veremos como obter o mesmo resultado utilizando o gparted. 
 Criaremos 3 partições no disco rígido recém instalado. 
Nº da partição Tipo Tamanho 
1 ext4 3 GB 
2 NTFS 2 GB 
3 ext4 1 GB 
 
O fidsk é um programa que requer privilégios de administrador para sua execução, portanto ao ser executado 
deve ser precedido pelo comando sudo para que execute com privilégios da conta root. Sua conta deve permitir o uso 
do sudo. 
 Para ver o estado da partição /dev/sdb pode ser executado o comando “”. 
fabio@ubuntu20:~$ sudo fdisk /dev/sdb -l 
Disco /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 setores 
Disk model: VBOX HARDDISK 
Unidades: setor de 1 * 512 = 512 bytes 
Tamanho de setor (lógico/físico): 512 bytes / 512 bytes Tamanho E/S (mínimo/ótimo): 512 
bytes / 512 bytes 
 
Criando partições com o fdisk 
 
O fdisk é um utilitário em modo texto que recebe comandos do teclado e vai configurando o disco em memória. 
Dessa forma, caso haja arrependimento das instruções fornecidas ao fdisk, basta abandonar a edição sem salvar, 
assim, nenhuma alteração será gravada em disco. 
Para iniciar a configuração do dispositivo /dev/sdb com o fdisk, deve ser executado o comando “sudo fdisk 
/dev/sdb”. Aparecerá o seguinte prompt: 
Comando (m para ajuda): 
solicitando que seja fornecido um comando para o fdisk. Pressionando a tecla m e teclando Enter é exibida a 
lista de comando do fdisk. Faça isso e veja os comandos que podem ser utilizados no utilitário. 
Vamos ver a sequência de comandos para criar a primeira partição (partição ext4 com 3 GB). 
1. Pressione a tecla n e depois Enter. Esse é o comando para criar uma nova partição. A seguir, é 
perguntado o tipo da partição. Uma partição primária é uma partição na qual será formatado um sistema 
de arquivos, enquanto uma partição secundária é uma partição na qual podem ser criadas outras 
partições. São permitidas apenas 4 partições no primeiro nível, assim, se forem necessárias mais que 
4 partições será preciso criar pelo menos uma partição secundária para comportar as demais. 
2. Pressione a tecla p e depois Enter. Com isso, será criada uma partição primária. Será perguntado o 
número da partição. 
3. Pressione a tecla 1 e depois Enter. Será perguntado o número do primeiro setor. Senão tiver absoluta 
certeza para escolher um número, aceite o valor padrão que o sistema alinhará a partição com o final 
da partição anterior. 
Sistemas Operacionais 
Marcio Quirino - 126 
 
4. Pressione Enter sem fornecer nenhum valor, aceitando a sugestão padrão para o setor inicial. Será 
perguntado o número do último setor. Em vez de fornecer o número do último setor, é mais conveniente 
digitar o caractere + seguido do tamanho da partição. 
5. Digite +3G e tecle Enter para criar a partição com 3 GB. 
 Seguirá uma mensagem informando que foi criada uma partição do tipo “Linux” e de tamanho 3 GB. Para ver 
a partição criada digite p e depois tecle Enter. Aparecerá uma informação como a seguinte: 
Disco /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 setores 
Disk model: VBOX HARDDISK 
Unidades: setor de 1 * 512 = 512 bytes 
Tamanho de setor (lógico/físico): 512 bytes / 512 bytes 
Tamanho E/S (mínimo/ótimo): 512 bytes / 512 bytes 
Tipo de rótulo do disco: dos 
Identificador do disco: 0x90c78077 
Dispositivo Inicializar Início Fim Setores Tamanho Id Tipo 
/dev/sdb1 2048 6293503 6291456 3G 83 Linux 
Faça a criação das partições 2 e 3, com 2 GB e 1 GB respectivamente. A sequência de comandos para a 
criação destas partições é: 
 Comando Descrição 
n Cria partição 
p Tipo primária 
2 Segunda partição 
 Primeiro setor (em branco para valor padrão) 
+2G Tamanho (2 GB) 
n Cria partição 
p Tipo primária 
3 Terceira partição 
 Primeiro setor (em branco para valor padrão) 
+1G Tamanho (1 GB) 
 Digite p seguido de Enter para ver como ficou a configuração. Deverá surgir uma saída como: 
 
Disco /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 setores 
Disk model: VBOX HARDDISK 
Unidades: setor de 1 * 512 = 512 bytes 
Tamanho de setor (lógico/físico): 512 bytes / 512 bytes 
Tamanho E/S (mínimo/ótimo): 512 bytes / 512 bytes 
Tipo de rótulo do disco: dos 
Identificador do disco: 0x90c78077 
Dispositivo Inicializar Início Fim Setores Tamanho Id Tipo 
/dev/sdb1 2048 6293503 6291456 3G 83 Linux 
/dev/sdb2 6293504 10487807 4194304 2G 83 
/dev/sdb3 10487808 12584959 2097152 1G 83 Linux 
Está quase tudo conforme o planejado, exceto que a partição 2 está como do tipo Linux, mas queremos uma 
partição do tipo NTFS (Windows). Para alterar o tipo de partição deve ser utilizado o comando t. 
1. Pressione t e tecle Enter. Será perguntada qual partição deve ser alterada. No caso queremos alterar 
a segunda partição. 
2. Pressione 2 e tecle Enter para selecionar a segunda partição. Será perguntado o código hexadecimal 
para a partição. Se não souber pressione L ver a relação. 
3. Pressione L e tecle Enter para ver a relação de códigos de partições. Pela relação, vemos que o NTFS 
possui código 7. 
4. Pressione 7 e tecle Enter. Surgirá uma mensagem informando que o tipo da partição foi alterado. 
Digite p seguido de Enter para ver como ficou a configuração final. Deverá surgir uma saída como: 
Linux 
Sistemas Operacionais 
Marcio Quirino - 127 
 
Disco /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 setores 
Disk model: VBOX HARDDISK 
Unidades: setor de 1 * 512 = 512 bytes 
Tamanho de setor (lógico/físico): 512 bytes / 512 bytes 
Tamanho E/S (mínimo/ótimo): 512 bytes / 512 bytes 
Tipo de rótulo do disco: dos Identificador do disco: 0x90c78077 
Dispositivo Inicializar Início Fim Setores Tamanho Id Tipo 
/dev/sdb1 2048 6293503 6291456 3G 83 Linux 
/dev/sdb2 6293504 10487807 4194304 2G 7 HPFS/NTFS/exFAT 
/dev/sdb3 10487808 12584959 2097152 1G 83 Linux 
Para salvar o trabalho digite w e tecle Enter. As informações serão gravadas em disco. Para sair sem alterar 
nada, basta digitar q e teclar Enter. 
Procure novamente por todas as entradas de dispositivos no diretório /dev que possua “sd” no nome utilizando 
o comando “ls -l /dev | grep sd”. Você verá o dispositivo /dev/sdb com todas as partições criadas. 
fabio@ubuntu20:~$ ls -l /dev | grep sd 
brw-rw---- 1 root disk 8, 0 ago 28 17:18 sda brw-rw---- 1 root disk 8, 
1 ago 28 17:18 sda1 brw-rw---- 1 root disk 8, 2 ago 28 17:18 sda2 brw-rw---- 1 
root disk 8, 5 ago 28 17:18 sda5 brw-rw---- 1 root disk 8, 16 ago 28 
18:24 sdb brw-rw---- 1 root disk 8, 17 ago 28 18:24 sdb1 brw-rw---- 1 root disk 
8, 18 ago 28 18:24 sdb2 brw-rw---- 1 root disk 8, 19 ago 28 18:24 sdb3 
 Criando partições com o gparted 
O gparted é um utilitário de interface gráfica que permite uma série de operações sobre partições, incluindo 
aumento, diminuição e movimentação de partições sem perda dos dados. 
Antes de utilizá-lo, é necessário verificar se ele está instalado em seu sistema. Caso não esteja, é necessário 
verificar como é sua instalação na distribuição que você está utilizando. 
Para instalar o gparted em distribuições derivadas do Debian, como é o caso do Ubuntu, basta executar os 
comandos: 
sudo apt-get update sudo apt-get install gparted 
O primeiro comando faz a sincronização da base de programas instalados com o servidor de atualizações, 
enquanto o segundo faz o download e a instalação da versão mais recente do gparted (e de tudo mais que o utilitário 
precisar). 
 Para a realização deste exercício, garanta que o disco /dev/sdb esteja sem nenhuma partição configurada. 
Você pode fazer isso executando “sudo fdisk /dev/sdb” e utilizando o comando d do fdisk para eliminar cada uma das 
partições. Não esquecer de sair com o comando w. 
 Para executar o gparted, basta procurá-lo na lista de utilitário da interface gráfica ou chamá-lo pela linha de 
comando. Como trata-se de um utilitário que precisa executar com privilégios de administrador, abra um terminal e 
coloque o gparted em execução com o comando “sudo gparted”. Deverá surgir a seguinte tela (ou semelhante): 
 
 Esta tela mostra o primeiro disco do sistema (/dev/sda). Para criar as partições no disco /dev/sdb, selecione 
/dev/sdb no canto superior direito. 
Sistemas Operacionais 
Marcio Quirino - 128 
 
 
Para criar uma nova partição, clique com o botão direito sobre a área não alocada e selecione Novo. Para criar 
a primeira partição de acordo com o solicitado (ext4 com 3 GB) preencha os dados conforme a figura abaixo: 
 
 
 Clique em Adicionar. 
 Para criar as partições seguintes, NTFS com 2 GB e ext4 com 1 GB, preencha as seguintes informações (uma 
vez para cada partição): 
 
 
Sistemas Operacionais 
Marcio Quirino - 129 
 
Após a configuração das 3 partições, o gparted deverá estar com uma aparência semelhante à da seguinte 
imagem: 
 
 A parte inferior da janela informa que existem 3 operações pendentes. Clique no menu “Editar  Aplicar todas as 
operações” para gravar as partições no disco. Ao final da operação a tela estará como mostrado na figura abaixo. 
 
Formatação 
O processo de criação de partições em um disco reserva espaço para o sistema de arquivos, 
mas ainda não faz com que o dispositivo possa ser utilizado. A fim de que seja possível fazer 
uso das partições criadas, é necessário criar uma estrutura para o sistema de arquivos. É um 
processo conhecido como formatação. 
 
Formatar uma partição Linux significa criar os grupos de blocos, cada um deles contendo seu 
superbloco, descritor do grupo, mapas de bits, i-nodes e reservar espaço para os blocos de 
dados. 
 
Formatação de partições em Linux 
 
Para execução deste exemplo, utilizaremos as partições criadas no exemplo anterior: 
 Partição Tipo Tamanho 
/dev/sdb1 ext4 3 GB 
/dev/sdb2 NTFS 2 GB 
/dev/sdb3 ext4 1 GB 
 
As partições estão criadas em um disco (/dev/sdb) de 10 GB. 
Sistemas Operacionais 
Marcio Quirino - 130 
 
 O programa do Linux para formatarpartições é o mkfs. Deve ser passado como parâmetro a partição que será 
formatada. As opções dependem do tipo da partição. 
fabio@ubuntu20:~$ sudo mkfs.ext4 /dev/sdb1 mke2fs 1.45.5 (07-Jan-2020) 
/dev/sdb1 contém um sistema de ficheiros ext4 criado em Fri Aug 28 19:02:54 2020 
Proceder mesmo assim? (y,N) y 
A criar sistema de ficheiros com 786432 4k blocos e 196608 inodes UUID do sistema de 
ficheiros: ec830215-63cd-42c6-a0fe-53e59511b2e6 Cópias de segurança de superblocos gravadas 
em blocos: 
 32768, 98304, 163840, 229376, 294912 
 
A alocar tabelas de grupo: pronto 
Gravando tabelas inode: pronto 
A criar diário (16384 blocos): concluído 
Escrevendo superblocos e informações de contabilidade de sistema de arquivos: 0concluído 
Mas para os tipos de partição mais usuais existem comandos específicos, que são extensões do mkfs e 
permitem a formatação passando como parâmetros apenas a partição a ser formatada, sem necessidade de opções. 
Alguns destes comandos são: mkfs.ext2, mkfs.ext3, mkfs.ext4, mkfs.fat, mkfs.vfat, mkfs.msdos, mkfs.ntfs, mkfs.minix, 
mkfs.bfs e mkfs.cramfs. 
 Para formatar, por exemplo, a partição /dev/sdb1 com o sistema de arquivos ext4, deve-se utilizar o comando 
“mkfs.ext4 /dev/sdb1”. 
Portanto, para formatar as partições especificadas na tabela acima, devem ser executados os comandos: 
sudo mkfs.ext4 /dev/sdb1 
sudo mkfs.ntfs /dev/sdb2 
sudo mkfs.ext4 /dev/sdb3 
O resultado do processamento será: 
fabio@ubuntu20:~$ sudo mkfs.ntfs /dev/sdb2 
Cluster size has been automatically set to 4096 bytes. 
Initializing device with zeroes: 100% - Done. 
Creating NTFS volume structures. 
mkntfs completed successfully. Have a nice day. 
fabio@ubuntu20:~$ 
fabio@ubuntu20:~$ sudo mkfs.ext4 /dev/sdb3 
mke2fs 1.45.5 (07-Jan-2020) 
/dev/sdb3 contém um sistema de ficheiros ext4 criado em Fri Aug 28 19:02:59 2020 
Proceder mesmo assim? (y,N) y 
A criar sistema de ficheiros com 262144 4k blocos e 65536 inodes UUID do sistema de ficheiros: 
fe19c1f6-5f27-43e4-b167-6d2136998823 Cópias de segurança de superblocos gravadas em blocos: 
 32768, 98304, 163840, 229376 
 
A alocar tabelas de grupo: pronto 
Gravando tabelas inode: pronto 
A criar diário (8192 blocos): concluído 
Escrevendo superblocos e informações de contabilidade de sistema de arquivos: 0/concluído 
 
Ao final deste processo, as partições estarão formatas e prontas para o recebimento de arquivos. 
Montagem do sistema de arquivos 
Muitos sistemas possuem dois ou mais discos ou partições. Além disso, muitos sistemas atuais 
permitem a utilização de diversos dispositivos de armazenamento simultaneamente, como discos ópticos e 
unidades USB, devendo se pensar em uma forma de acessar os diferentes sistemas de arquivos. 
Uma solução está em manter cada sistema separado e encontrar uma forma de referenciá-los, 
conforme a maneira adotada pela Microsoft para o sistema operacional Windows. Nela, os dispositivos são 
identificados por uma letra seguido pelo caractere dois pontos. 
 
 
Sistemas Operacionais 
Marcio Quirino - 131 
 
Exemplo 
Uma partição de um disco rígido pode ser identificada por C:, uma unidade óptica por D:, um dispositivo USB 
por G:, e assim por diante. Cada unidade possui seu próprio diretório raiz, arquivos e subdiretórios. Nessa solução, o 
usuário precisa especificar tanto o dispositivo quanto o arquivo. 
Outro meio, adotado pelo Linux, é fazer com que o sistema de arquivos de um dispositivo/partição 
seja montado sobre a árvore de diretórios do sistema. Dessa forma, uma unidade ótica poderia ser montada, 
por exemplo, no diretório /mnt, enquanto um dispositivo USB poderia ser montado no diretório /media/usb1. 
A figura abaixo mostra a estrutura do sistema de arquivos descrito (a) no Microsoft Windows e (b) no 
Linux. 
Exemplo de montagem de dispositivos (a) no MS Windows e (b) no Linux. 
Montagem de partições em Linux 
 
Para execução deste exemplo, utilizaremos as partições criadas e formatadas nos exemplos anteriores: 
 Partição Tipo Tamanho 
/dev/sdb1 ext4 3 GB 
/dev/sdb2 NTFS 2 GB 
/dev/sdb3 ext4 1 GB 
 
As partições estão criadas em um disco (/dev/sdb) de 10 GB. 
Sistemas Operacionais 
Marcio Quirino - 132 
 
 No Microsoft Windows®, cada letra de unidade (C:, D:, E:) identifica um sistema de arquivos em uma partição 
de disco ou em um dispositivo, enquanto no Linux as partições são acessadas em diretórios, conhecidos como pontos 
de montagem, e que fazem parte da estrutura do sistema de arquivos raiz. 
Cada partição pode ser montada em qualquer diretório. 
No caso de um sistema de arquivos cheio, pode-se copiar o conteúdo de um diretório para outro sistema de 
arquivos, apagar o conteúdo do diretório original e montar partição onde foram copiados os arquivos naquele local. 
 A adição de novas partições ou substituição de discos rígidos não afeta a ordem de identificação dos discos e 
pontos de montagem. 
Montagem de sistema de arquivos 
 A montagem de um sistema de arquivos é feita por intermédio do comando mount, cuja sintaxe é: 
mount [dispositivo] [ponto de montagem] [opções] 
 Sendo: 
• dispositivo → Identificação do dispositivo/partição que será montado. 
• ponto de montagem → Diretório de onde o dispositivo/partição será montado. 
 
Algumas opções: 
• -t [tipo] → Tipo do sistema de arquivos utilizado (ext2, ext3, ext4, vfat, iso9660, etc.). 
• -r → Monta a partição como somente leitura. 
• -w → Monta a partição como leitura/gravação. É o padrão. 
Desmontagem de sistema de arquivos 
 Para desmontar um sistema de arquivos utiliza-se o comando umount, cuja sintaxe é: 
 umount [dispositivo ou ponto de montagem] 
 Montando e desmontando sistemas de arquivos 
 Para a montagem dos sistemas de arquivos criados anteriormente, utilizaremos os seguintes pontos de 
montagem: 
 Partição Ponto de montagem 
/dev/sdb1 /extra/b1 
/dev/sdb2 /extra/b2 
/dev/sdb3 /extra/b3 
 O primeiro passo é montar a estrutura de diretórios que será utilizada para a montagem dos sistemas de 
arquivos. Os comandos utilizados para a criação dos diretórios, que serão estuados adiante, são: 
sudo mkdir -p /extra/b1 
sudo mkdir /extra/b2 
sudo mkdir /extra/b3 
 Uma vez criados os pontos de montagem, basta utilizar o comando mount para montar as partições: 
sudo mount -t ext4 /dev/sdb1 /extra/b1 
sudo mount -t ntfs /dev/sdb2 /extra/b2 
sudo mount -t ext4 /dev/sdb3 /extra/b3 
 Neste momento, temos os sistemas de arquivos formatados e montados, prontos para utilização. 
 Uma forma de verificar os sistemas de arquivos montados e prontos para uso é por intermédio do comando “df 
-h”. Na listagem a seguir podemos ver o resultado do comando. Para facilitar a leitura, foram omitidos alguns sistemas 
de arquivos montados por padrão. 
Sistemas Operacionais 
Marcio Quirino - 133 
 
fabio@ubuntu20:~$ df -h 
Sist. Arq. Tam. Usado Disp. Uso% Montado em udev 967M 0 967M 0% 
/dev tmpfs 199M 1,4M 198M 1% 
/run 
/dev/sda5 15G 6,1G 7,4G 46% / 
/dev/sda1 511M 4,0K 511M 1% /boot/efi 
/dev/sdb1 2,9G 9,0M 2,8G 1% /extra/b1 
/dev/sdb2 2,0G 11M 2,0G 1% /extra/b2 
/dev/sdb3 976M 2,6M 907M 1% /extra/b3 
 Para desmontar os sistemas de arquivos montados, utiliza-se o comando umount. 
sudo umount /dev/sdb1 
sudo umount /dev/sdb2 
sudo umount /dev/sdb3 
 Podemos verificar que os sistemas de arquivos foram desmontados executando novamente o comando “df -h”. 
 Montagem automática de sistemas de arquivos 
O arquivo /etc/fstab permite que as partições do sistema sejam montadas facilmente, especificando somente 
o dispositivo ou o ponto de montagem. É possível também configurar para que os sistemas de arquivos sejam montados 
automaticamente duranteo boot. Este arquivo contém parâmetros sobre as partições que são lidos pelo comando 
mount. 
Cada linha deste arquivo contém a partição a ser montada, o ponto de montagem, o sistema de arquivos 
utilizado pela partição e outras opções. O arquivo possui a seguinte estrutura: 
 Sistema_de_arquivos Ponto_de_Montagem Tipo Opções dump ordem 
/dev/sda1 / ext4 defaults 0 1 
/dev/sda2 /home ext4 defaults 0 2 
/dev/sda3 /extra vfat defaults,noauto,rw 0 0 
/dev/sda4 none swap sw 0 0 
 
Em que: 
• Sistema de Arquivos → Partição a ser montada. 
• Ponto de montagem → Diretório onde a partição será montada. 
• Tipo → Tipo de sistema de arquivos utilizado na partição que será montada. 
• Opções → Especifica as opções usadas com o sistema de arquivos. Algumas opções: 
o defaults → Utiliza valores padrões de montagem. 
o noauto → Não monta os sistemas de arquivos durante a inicialização. o ro → Monta como 
somente leitura. o user → Permite que usuários montem o sistema de arquivos. 
o sync → Faz com que os dados sejam gravados imediatamente na unidade. 
• dump → Especifica se será feito backup com utilitário dump, se estiver instalado. Podem ser colocados 
os valores 0 (desativa backup) ou 1 (ativa backup). 
• ordem → Define a ordem que os sistemas de arquivos serão verificados na inicialização do sistema. 
Se usar 0, o sistema de arquivos não é verificado. O primeiro sistema de arquivos que deverá ser 
verificado é o raiz. 
 Para o exemplo acima, após configurar o arquivo /etc/fstab, basta digitar o comando “mount /dev/sda3” ou 
“mount /extra” para que a partição “/dev/sda3” seja montada no ponto de montagem “/extra”. Não é necessário 
especificar o sistema de arquivos da partição, pois o mount verificará no arquivo /etc/fstab. 
 Partição de swap (memória virtual) 
 A partição de swap é utilizada para oferecer o suporte à memória virtual, em adição à memória RAM do 
sistema. 
Sistemas Operacionais 
Marcio Quirino - 134 
 
 Quando um processo começa a encher a memória RAM, o sistema operacional move automaticamente os 
dados que não estão sendo usados para a partição de swap e libera parte da memória RAM para continuar carregando 
os dados necessários. Quando os dados movidos para a partição de swap são solicitados, o sistema operacional os 
move da partição de swap de volta para a memória RAM. 
 Criando o swap em uma partição 
 No disco criado anteriormente (/dev/sdb), vamos utilizar o espaço restante para criar a partição /dev/sdb4, 
ocupando o restante do disco. Vamos ainda definir o tipo da partição como swap para que possa ser utilizada em 
adição à memória RAM do sistema. 
 Para criar a partição, utilize o fdisk executando-o em um terminal. Para isso, digite no shell o comando “sudo 
fdisk /dev/sdb”. Forneça a seguinte sequência de comandos: 
 Comando Descrição 
n Cria partição 
p Tipo primária 
 Primeiro setor (em branco para valor padrão) 
 Último setor (em branco para utilizar todo o restante do disco) 
t Alterar o tipo da partição 
4 Selecionar a partição 4 para alteração do tipo 
L Verificar o código hexadecimal para partição de swap 
82 Identifica a partição como swap 
w Sai gravando as alterações 
 
Como ainda restavam 4 GB de espaço livre no disco, foi criada uma partição de 4GB do tipo Linux swap. 
O programa usado para formatar uma partição de swap é o mkswap. Para criar uma partição de swap em 
“/dev/sdb4”, por exemplo, deve-se executar o comando “sudo mkswap /dev/sdb4”. 
 A opção “-c” pode ser usada com o mkswap para verificar se existem clusters danificados na partição. 
 Com a partição de swap formatada, o comando “sudo swapon /dev/sdb4” deve ser utilizado para ativar a 
partição de swap. 
 O swapon ativa a partição de swap até a próxima reinicialização do sistema. Para ativar esta partição de swap 
para todas as seções, é necessário acrescentar no arquivo /etc/fstab uma linha como a abaixo: 
 /dev/sdb4 none swap sw 0 0 
 Se utilizar mais do que uma partição de swap, pode ser útil o uso da opção “-p NUM”, que especifica a 
prioridade em que a partição de swap será usada. Partições com número maior serão usadas primeiro. Devem ser 
utilizados números maiores para partições mais rápidas e números menores para partições mais lentas. 
 Caso precise desativar a partição de swap, use o comando: “swapoff <partição>”. Para o nosso exemplo, o 
comando seria “sudo swapoff /dev/sdb4”. 
 Criando o swap em um arquivo 
Também é possível criar um arquivo para ser utilizado como apoio à memória virtual. 
Utilize o comando dd para criar um arquivo com o tamanho desejado. Os parâmetros do dd são: 
• if → Arquivo fonte de onde os dados serão copiados. 
• of → Arquivo destino para onde os dados serão copiados. 
• bs → Quantidade de dados a ser copiado por bloco. 
• count → Quantidade de blocos a ser copiado. 
 Para criar o arquivo /troca com 512 MB contendo valores o (zero), executar o comando: 
Sistemas Operacionais 
Marcio Quirino - 135 
 
 sudo dd if=/dev/zero of=/troca bs=1024 count=524288 
 Após, executar o comando “sudo mkswap /troca” para formatar o arquivo. Feito isso, o sistema de arquivos 
swap estará criado e pronto para ser utilizado. 
 Ativar o arquivo de swap com o comando “sudo swapon /troca”. 
 Para conferir a qualquer momento se o tamanho da memória virtual foi modificado pode-se utilizar o comando 
“free”. 
Podem ser usadas partições de swap e arquivos de swap ao mesmo tempo. 
O swapon ativa o arquivo de swap até a próxima reinicialização do sistema. Para ativar este arquivo de swap 
para todas as seções, é necessário acrescentar no arquivo /etc/fstab uma linha como a abaixo: 
 /troca none swap sw 0 0 
 Outros comandos para gerenciamento de partições 
Além dos comandos vistos nos exemplos para criação e gerenciamento de partições, o Linux possui 
outros utilitários que podem ser úteis para a administração do sistema. Vejamos alguns destes comandos. 
A. fsck 
Utilitário utilizado para verificar e, se necessário, corrigir um sistema de arquivos. Se não for 
informado o tipo do sistema de arquivos, o fsck procurará por essa informação no 
arquivo /etc/fstab. 
/etc/fstab 
Arquivo que contém informações sobre os sistemas de arquivos a serem utilizados no sistema, como a 
partição em que se encontra, o tipo do sistema de arquivos, o ponto de montagem etc. 
Algumas opções: 
• -t → Especifica o tipo do sistema de arquivos; 
• -C → Mostra uma barra de progresso da verificação. Não está disponível para todos os 
sistemas de arquivos; 
• -V → Gera saída detalhada das operações realizadas. 
Exemplo: 
$ sudo fsck -t ext4 /dev/sdb1 
fsck de util-linux 2.34 
e2fsck 1.45.5 (07-Jan-2020) 
/dev/sdb1: limpo, 11/196608 ficheiros, 31036/786432 blocos 
B. df 
Utilitário para exibição do espaço livre/ocupado por cada sistema de arquivos montados. Informa 
a partição onde o sistema de arquivos reside, o tamanho do sistema de arquivos, os espaços 
utilizado e disponível, o percentual de uso e onde se localiza o ponto de montagem do sistema 
de arquivos. 
Algumas opções: 
• -h → Mostra o espaço livre/ocupado em MB, KB, GB em vez de blocos; 
• -k → Lista em Kbytes; 
• -l → Somente lista sistema de arquivos locais; 
• -m → Lista em Mbytes. 
 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 136 
 
Exemplo: 
$ df -h 
Sist. Arq. Tam. Usado Disp. Uso% Montado em 
Udev 967M 0 967M 0% /dev 
tmpfs 199M 1,3M 198M 1% /run 
/dev/sda5 15G 6,7G 6,9G 50% / 
Compartilhada 446G 430G 17G 97% /media/sf_Compartilhada 
C. lsblk 
Utilitário que lista informações sobre os dispositivos de bloco do sistema, excetuando-se os 
discos de RAM. As informações incluem o tamanho total da partição/blocoe o ponto de 
montagem, se o sistema de arquivos estiver montado. Este comando não informa o espaço em 
disco utilizado/livre nos sistemas de arquivos. 
Algumas opções: 
• -a → Lista todos os dispositivos, incluindo discos de RAM; 
• -b → Informa o tamanho em bytes; 
• -f → Exibe informações sobre os sistemas e arquivos. 
Exemplo: 
 
$ lsblk 
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 
das 8:0 0 15G 0 disk 
├─sda1 8:1 0 512M 0 part /boot/efi 
├─sda2 8:2 0 1K 0 part 
└─sda5 8:5 0 14,5G 0 part / 
 
sdb 8:16 0 10G 0 disk 
├─sdb1 8:17 0 3G 0 part 
├─sdb2 8:18 0 2G 0 part /extra/b2 
├─sdb3 8:19 0 1G 0 part 
└─sdb4 8:20 0 4G 0 part 
sr0 11:0 1 1024M 0 rom 
3. Ferramentas de gerenciamentos de arquivos do Linux 
Conceitos 
O Linux é um sistema operacional, ou melhor, o núcleo do sistema. É o responsável pelo 
gerenciamento dos dispositivos e recursos do sistema, oferecendo para os softwares que executam acima 
dele chamadas de sistema que transformam o verdadeiro hardware em uma máquina mais fácil de ser 
utilizada. 
O Linux é a base, mas ainda faltam softwares que forneçam a funcionalidade que os usuários 
desejam de um sistema. A fim de oferecer esta funcionalidade, organizações e pessoas empacotam um 
conjunto de softwares que, com o núcleo do sistema (o Linux), formam um sistema completo que pode ser 
instalado e utilizado pelas pessoas. 
Saiba mais 
Esse conjunto de softwares é conhecido como distribuição. 
Cada distribuição é livre para escolher os pacotes de software que serão instalados, e isso se torna 
mais evidente com relação ao ambiente gráfico. Existem várias interfaces gráficas que podem ser utilizadas, 
cada uma configurada com diferentes softwares. 
 
Sistemas Operacionais 
Marcio Quirino - 137 
 
Exemplo 
Algumas das interfaces gráficas mais populares para o Linux são: GNOME, KDE, Cinnamon, MATE e XFCE. 
O Linux também possui uma série de comandos em modo texto que permitem realizar praticamente 
qualquer tarefa no sistema, e, ao contrário das interfaces gráficas, são utilitários padrão (ou quase isso) 
disponíveis para utilização em qualquer distribuição. Por essa razão, estudaremos os comandos em modo 
texto, que permitirão que você possa utilizar qualquer sistema Linux. 
Durante a inicialização, o Linux monta um sistema de arquivos conhecido como sistema de arquivos 
raiz. Ele tem início em um diretório representado pela barra de divisão “/”, que recebe o nome de root (raiz). 
Atenção 
Não confundir o diretório root com o usuário root (administrador do sistema). 
Os demais sistemas de arquivos que forem necessários para a execução do sistema serão montados 
em pontos de montagem da hierarquia de diretórios. 
Saiba mais 
Para alguns sistemas operacionais, como o Microsoft Windows, um arquivo torna-se oculto quando é ativada 
uma de suas propriedades. Ou seja, ser oculto é uma propriedade. 
O Linux trata arquivos ocultos de uma forma diferente. Um arquivo oculto nesse sistema operacional 
é aquele que inicia com o caractere ponto “.”. Esse tipo de arquivo não aparece em listagens do conteúdo 
dos diretórios, a não ser que seja explicitamente solicitado. 
Comandos para manipulação de diretórios 
A. ls 
Lista o conteúdo do diretório corrente. 
Sintaxe: ls [opções] [caminho] 
Se caminho for informado, mostra o conteúdo do diretório caminho, senão mostra o conteúdo do 
diretório corrente. 
Algumas opções: 
• -a → Lista todos os arquivos de um diretório, incluindo arquivos ocultos; 
• -h → Mostra o tamanho dos arquivos em Kbytes, Mbytes, Gbytes; 
• -i → Mostra o número do i-node de cada arquivo. 
• -l → Mostra mais informações, como lista as permissões, data de modificação, donos, 
grupos etc. 
• -R → Lista diretórios e subdiretórios recursivamente. 
• -r → Inverte a ordem de classificação. 
• -c → Classifica pela data de alteração. 
• --help → Mostra uma tela de ajuda. 
Exemplo: 
fabio@ubuntu20:~$ ls 
‘Área de Trabalho’ Downloads Modelos Público teste Vídeos Documentos Imagens Música snap 
teste.txt 
fabio@ubuntu20:~$ ls -a 
. .gnupg .ssh 
.. Imagens .sudo_as_admin_successful 
‘Área de Trabalho’ .joe_state teste 
.bash_history .lesshst teste.txt 
Sistemas Operacionais 
Marcio Quirino - 138 
 
.bash_logout .local .vboxclient-clipboard.pid 
.bashrc Modelos .vboxclient-display-svga-x11.pid 
.cache Música .vboxclient-draganddrop.pid 
.config .profile .vboxclient-seamless.pid 
Documentos Público Vídeos 
Downloads snap 
 
fabio@ubuntu20:~$ ls -lh 
total 20M 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 'Área de Trabalho' 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Documentos 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Downloads 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Imagens 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Modelos 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Música 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Público 
-rwxr-xr-x 1 fabio fabio 20M ago 29 14:30 snap 
drwxrwxr-x 2 fabio fabio 4,0K ago 14 10:14 teste 
-rw-rw-r-- 1 fabio fabio 5,0K ago 13 17:21 teste.txt 
drwxr-xr-x 2 fabio fabio 4,0K ago 9 20:18 Vídeos 
B. pwd 
Mostra o caminho do diretório de trabalho. 
Exemplo: 
$ pwd 
/home/fabio 
No exemplo, o comando pwd mostrou que o diretório de trabalho é o /home/fabio, ou seja, o 
diretório padrão de trabalho do usuário fabio (diretório home de fabio). 
C. cd 
Altera o diretório atual de trabalho. 
Sintaxe: cd [diretório] 
Altera o diretório de trabalho para o passado como parâmetro. Se o diretório de destino não for 
especificado, vai para o diretório home do usuário. 
Exemplo: 
$ pwd 
/var/spool 
$ cd 
$ pwd 
/home/fabio 
$ cd /etc 
$ pwd 
/etc 
No caso acima, o diretório de trabalho era /var/spool. Ao executar o comando “cd” o diretório de 
trabalho mudou para /home/fabio. Ao executar o comando “cd /etc” o diretório de trabalho mudou 
para /etc. 
Algumas utilizações do comando cd: 
• cd / → Vai para o diretório raiz (root); 
• cd .. → Sobe um nível na árvore de diretórios; 
• cd - → Retorna para o diretório que estava antes de entrar no diretório atual. 
D. mkdir 
Cria um ou mais diretórios. 
Sistemas Operacionais 
Marcio Quirino - 139 
 
Sintaxe: mkdir [caminho/diretório] 
Na qual caminho é o local em que o diretório será criado e diretório é o nome do diretório a ser 
criado. 
Algumas opções: 
• -p → Caso os diretórios dos níveis acima não existam, serão criados. 
Exemplo: 
$ mkdir a/b/c 
mkdir: não foi possível criar o diretório “a/b/c”: Arquivo ou diretório não encontrado 
$ mkdir -p a/b/c 
$ mkdir a/b/c/d 
No exemplo, o primeiro comando (mkdir a/b/c) falhou porque tentou criar, a partir do diretório 
corrente, o diretório “c” dentro do caminho “a/b”, mas o caminho “a/b” não existe. O segundo 
comando (mkdir -p a/b/c) funcionou por causa do parâmetro -p, que forçou a criação dos diretórios 
“a” e “a/b” caso não existissem. O terceiro comando criou o diretório “d” dentro do caminho “a/b/c”. 
E. rmdir 
Remove um diretório vazio. 
Sintaxe: rmdir [caminho/diretório] 
Exemplo: 
$ rmdir a/b/c/d 
$ rmdir a 
rmdir: falhou em remover 'a': Diretório não vazio 
Neste caso, o primeiro comando funcionou e removeu o diretório “d” que estava no caminho 
“a/b/c”. O segundo comando não funcionou porque tentou remover o diretório “a”, que não está 
vazio. Para a remoção de diretórios que contenham arquivos e/ou subdiretórios, consulte o 
comando rm. 
Comandos para manipulação de arquivos 
Clique nas barras para ver as informações. 
A. rm 
O comando rm é utilizado para apagar arquivos. Pode ser utilizado também para apagar 
diretórios e subdiretórios recursivamente. 
Sintaxe: rm [opções] arquivo/diretório 
Algumas opções: 
• -i → Pergunta antes de remover;• -v → Mostra os nomes dos arquivos/diretórios conforme são removidos; 
• -r → Remove arquivos e diretórios recursivamente; 
• -f → Remove sem perguntar. 
Utilizando a opção “-r” é possível apagar diretórios recursivamente. Desta forma, sempre que for 
necessário apagar um diretório que contenha arquivos, o comando “rm -r” deve ser utilizado no 
lugar do comando “rmdir”. 
Exemplo: 
$ rm -rf a 
Sistemas Operacionais 
Marcio Quirino - 140 
 
Neste caso, o arquivo a é removido, pois sendo a um diretório, ele será apagado, assim como 
todos os seus arquivos e subdiretórios, sem que seja solicitada a confirmação. 
B. cp 
Copia arquivos e diretórios. É necessário especificar tanto a origem quanto o destino do 
arquivo/diretório a ser copiado. 
Sintaxe: cp [opções] origem destino 
Na qual origem indica o arquivo ou diretório a ser copiado e destino indica o local para onde deve 
ser copiado. 
Algumas opções: 
• -i → Pergunta antes de substituir um arquivo existente; 
• -f → Substitui arquivos existentes sem perguntar; 
• -r → Copia arquivos dos diretórios e subdiretórios da origem para o destino; 
• -R → Copia arquivos e diretórios recursivamente, assim como os arquivos especiais FIFO 
e dispositivos; 
• -v → Mostra os nomes dos arquivos que estão sendo copiados; 
• -p → Preserva atributos do arquivo; 
• -u → Copia somente se o arquivo de origem é mais novo que o arquivo de destino ou 
quando o arquivo de destino não existe. 
Exemplo: 
$ cp /etc/fstab . 
$ cp teste.txt outro.txt 
O primeiro exemplo copia o arquivo fstab que está no diretório /etc para o diretório de trabalho 
(“.”). O segundo exemplo copia o arquivo teste.txt para outro.txt no mesmo diretório. 
C. mv 
Move ou renomeia arquivos e diretórios. 
Sintaxe: mv [opções] origem destino 
Em que origem indica o arquivo ou diretório a ser movido e destino indica o local para onde deve 
ser movido. 
Algumas opções: 
• -f → Substitui o destino sem perguntar; 
• -i → Pergunta antes de substituir; 
• -v → Mostra os nomes dos arquivos que estão sendo movidos; 
• -u → Move somente se o arquivo origem for mais novo que o arquivo destino, ou se o 
arquivo não existir no destino. 
Exemplo: 
$ mv teste.txt outro.txt 
$ mv outro.txt a/b/ 
No exemplo, o primeiro comando renomeia o arquivo teste.txt para outro.txt. O segundo comando 
move o arquivo outro.txt para o diretório b que está dentro do diretório a. 
D. cat 
Mostra o conteúdo de um arquivo. 
Sistemas Operacionais 
Marcio Quirino - 141 
 
Sintaxe: cat [opções] arquivo 
Algumas opções: 
• -n → Mostra o número das linhas enquanto o conteúdo do arquivo é exibido; 
• -s → Não mostra mais que uma linha em branco entre um parágrafo e outro. 
Exemplo: 
$ cat /etc/host.conf 
# The "order" line is only used by old versions of the C library. 
order hosts,bind 
multi on 
E. find 
Procura por arquivos/diretórios no disco, podendo ser por intermédio de diversas opções, como 
nome, data de modificação, tamanho etc. 
Sintaxe: find [diretório] [opções/expressão] 
Em que diretório é o local onde se inicia a busca, percorrendo todos os seus subdiretórios. 
Algumas opções/expressão: 
• -name [expressão] → Procura pelo nome [expressão]; 
• -amin [num] → Procura por arquivos que foram acessados [num] minutos atrás. Caso for 
antecedido por “-” (menos), procura por arquivos que foram acessados entre [num] 
minutos atrás até agora; 
• -atime [num] → Procura por arquivos que foram acessados [num] dias atrás. Caso for 
antecedido por “-” (menos), procura por arquivos que foram acessados entre [num] dias 
atrás e a data atual; 
• -gid [num] → Procura por arquivos que possuam a identificação numérica do grupo igual 
a [num]; 
• -group [nome] → Procura por arquivos que possuam a identificação de nome do grupo 
igual a [nome]; 
• -uid [num] → Procura por arquivos que possuam a identificação numérica do usuário igual 
a [num]; 
• -user [nome] → Procura por arquivos que possuam a identificação de nome do usuário 
igual a [nome]; 
• -mmin [num] → Procura por arquivos que tiveram seu conteúdo modificado há [num] 
minutos. Caso for antecedido por “-” (menos), procura por arquivos que tiveram seu 
conteúdo modificado entre [num] minutos atrás até agora; 
• -mtime [num] → Procura por arquivos que tiveram seu conteúdo modificado há [num] dias. 
Caso for antecedido por “-” (menos), procura por arquivos que tiveram seu conteúdo 
modificado entre [num] dias atrás até agora; 
• -perm [modo] → Procura por arquivos que possuam os modos de permissão [modo]; 
• -size [num] → Procura por arquivos que tiverem o tamanho [num]. [num] pode ser 
antecedido de “+” ou “-” para especificar um arquivo maior ou menor que [num]. 
Exemplo: 
$ find /home -name outro.txt 
/home/fabio/a/b/outro.txt 
Neste caso, o comando procura por um arquivo ou diretório de nome outro.txt, fazendo a busca 
a partir do diretório /home. O retorno do comando informa que o arquivo se encontra no 
diretório /home/fabio/a/b. 
Sistemas Operacionais 
Marcio Quirino - 142 
 
Links simbólicos e hardlinks 
Links simbólicos são entradas de diretório que, ao invés de indicar um local no disco onde se 
encontram dados de um arquivo, apontam para outras entradas de diretórios. Funcionam como atalho para 
um arquivo ou diretório. 
Para efeito de utilização, não faz diferença acessar um arquivo diretamente ou por intermédio de um 
link simbólico. O processo é totalmente transparente para o usuário. 
Tais entradas de diretório são bastante úteis para compatibilizar sistemas que procuram por arquivos 
em diferentes locais. No lugar de manter cópias do mesmo arquivo, cria-se links simbólicos nos diferentes 
locais onde os arquivos podem ser procurados, economizando espaço em disco e evitando inconsistências 
que poderiam ser provocadas por arquivos que deveriam ser iguais mais possuem conteúdo diferente. 
No Linux, um arquivo é acessado por meio de seu i-node. Uma entrada de diretório de arquivo deve 
apontar para o i-node do arquivo de forma a poder acessar o seu conteúdo. O sistema de arquivos do Linux 
permite que diferentes entradas de diretórios apontem para o mesmo i-node, fazendo com que essas 
entradas apontem, na prática, para o mesmo arquivo. 
Dica 
A maneira de fazer com que diferentes entradas apontem para o mesmo arquivo se dá através de 
um hardlink (denominado link duro por alguns autores). 
Para criar links simbólicos e hardlinks, utiliza-se o comando ln, cuja sintaxe é: 
 
ln [opções] alvo [nome_do_link/diretório] 
• alvo é o arquivo/diretório que será referenciado pelo link; 
• nome_do_link/diretório é o nome do link que será criado ou o diretório onde será criado o link 
com o mesmo nome do alvo. 
Algumas opções: 
• -s → Cria um link simbólico; 
• -v → Mostra o nome de cada arquivo antes de fazer o link; 
• -d → Cria hardlink para diretórios. 
Suponha que em um diretório exista um arquivo de nome “documento.txt”. O comando abaixo cria 
no mesmo diretório um link simbólico chamado “simbolico.txt” que aponta para “documento.txt”. 
$ ln -s documento.txt simbolico.txt 
$ ls -lh 
total 4,0K 
-rw-r--r-- 1 fabio fabio 2,8K ago 29 21:05 documento.txt 
lrwxrwxrwx 1 fabio fabio 13 ago 29 21:21 simbolico.txt -> documento.txt 
Observe pela saída do comando “ls -lh” que “simbolico.txt” é um link simbólico para “documento.txt”. 
Para criar um hardlink de nome “hard.txt” para o arquivo “documento.txt”, é utilizado também o 
comando ln, mas sem a opção -s. 
$ ln documento.txt hard.txt 
$ ls -lhi 
total 8,0K 
404662 -rw-r--r-- 2 fabio fabio 2,8K ago 29 21:05 documento.txt 
404662 -rw-r--r-- 2 fabio fabio 2,8K ago 29 21:05 hard.txt 
396432 lrwxrwxrwx 1 fabio fabio 13 ago 29 21:21 simbolico.txt -> documento.txt 
Sistemas Operacionais 
Marcio Quirino - 143 
 
A opção -i do comando ls (para listar o conteúdo do diretório) informa o número do i-node do arquivo. 
Observe no exemplo acima que ambos “documento.txt” e “hard.txt”possuem o mesmo número de i-node 
(404662), ou seja, ambos apontam para o mesmo arquivo. 
Qualquer alteração feita no arquivo sendo acessado por qualquer um dos 3 nomes (“documento.txt”, 
“simbolico.txt” ou “hard.txt”) acarretará alteração para todos, já que apontam para o mesmo arquivo. 
Observe também, no último exemplo, para no número 2 antes do nome do dono do arquivo (fabio). 
Isso indica que existem duas entradas de diretório apontando para o mesmo i-node (404662). O link 
simbólico não é computado. 
Resumindo 
Isso significa que o sistema de arquivos mantém uma contagem de quantas entradas de diretório estão 
apontando para o mesmo i-node (o mesmo arquivo). 
Assim, se alguma das entradas de diretório for eliminada por rm ou por rmdir, o arquivo/diretório será 
efetivamente eliminado somente se existir uma única entrada de diretório apontada para ele. Se houver mais 
de um hardlink para o arquivo, somente a entrada de diretório é apagada. 
4. Funcionamento dos principais editores de arquivos do 
Linux 
ASCII 
ASCII (American Standard Code for Information Interchange - Código Padrão Americano para o Intercâmbio 
de Informação) é um padrão de codificação de caracteres criado para padronizar a forma como os computadores 
representam letras, números, acentos, sinais diversos e alguns códigos de controle. 
Editor de arquivos x processador de textos 
Arquivos de texto puro e documentos criados por processadores de texto como o Microsoft Word ou 
o LibreOffice Writer possuem diferenças significativas. 
Um arquivo de texto puro contém caracteres ASCII, cujo conteúdo pode ser entendido visualizando 
diretamente o conteúdo do arquivo, sem necessidade de conversões ou interpretações. 
Saiba mais 
Alguns arquivos deste tipo, como o HTML, possuem marcações de controle, mas todos compostos por 
caracteres ASCII. 
Já documentos criados por um processador de texto possui conteúdo com formato específico, 
possuindo vários caracteres de controle e, comumente, informações binárias. Neste tipo de arquivo, é 
possível seleção de diferentes fontes para texto, com diferentes tamanhos e formatações (negrito, itálico 
etc.), além da incorporação de tabelas, imagens e links, entre outros. 
Um processador de textos muito utilizado por usuários do Linux é o Writer, ferramenta integrante do 
pacote LibreOffice, um software livre de escritório com software para processamento de texto, planilha 
eletrônica, apresentação, desenho, banco de dados, edição de equações matemáticas etc. 
 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 144 
 
Arquivos de texto puro são comumente utilizados para configuração de sistemas em um ambiente 
Linux, e um administrador de sistemas precisa saber como editar tais arquivos. Neste módulo, 
conheceremos alguns dos principais editores de texto puro disponíveis para utilização em sistemas Linux. 
BSD 
Berkeley Software Distribution (BSD) é um sistema operacional Unix desenvolvido na Universidade da 
Califórnia em Berkeley. 
vim 
Vim é uma abreviação de Vi Improved (Vi Melhorado), sendo uma melhoria do editor de textos vi, 
criado em 1976 para o BSD. O vi destacou-se por ser um editor pequeno e leve, podendo ser colocado junto 
de mídias com pouco espaço de armazenamento para ser executado durante operações de manutenção de 
emergência, ou em sistemas com pouco recurso computacional disponível. Por essas características, é um 
editor de textos disponível em toda distribuição Linux, que pode ser utilizado tanto em emergências quanto 
no dia a dia para alterar arquivos de configuração do sistema. 
O vim é um editor modal, ou seja, possui diferentes modo de operação (comando e edição) e as 
teclas possuem diferentes funções em cada modo. Ele é executado a partir de um terminal, sendo colocado 
em execução digitando o comando “vim nome_do_arquivo” ou “vi nome_do_arquivo”, no 
qual nome_do_arquivo é o nome do arquivo que será executado. A opção por utilizar vi ou vim depende da 
distribuição. 
Exemplo 
No Ubuntu 20.04 LTS, utilizado em nossos exemplos, deve ser aplicada a forma “vi nome_do_arquivo”. 
Sempre que o editor é aberto, ele inicia no modo de comando. Nesse modo, quando se digita algo 
no teclado, são enviados comandos para que o editor execute determinadas ações sobre o texto que está 
sendo editado. Quando estiver no modo de edição, todo o texto digitado será inserido na posição onde se 
encontra o cursor. 
Dica 
Para sair do modo de edição e voltar ao modo de comando, pressione a tecla <Esc>. 
Principais comandos do vim 
Para que você possa utilizar o vim, serão apresentados alguns comandos básicos para utilização 
deste poderoso editor de textos. 
Clique nas barras para ver as informações. 
A. Entrar em modo de edição 
• i → Insere na posição atual. 
• I → Insere no começo da linha. 
• a → Acrescenta na posição atual. 
• A → Acrescenta ao final da linha. 
• o → Insere na linha abaixo, criando uma nova linha. 
• O → Insere na linha acima, criando uma nova linha. 
• cc → Deleta a linha e entra no modo de inserção. 
• C → Deleta linha a frente do cursor e entra em modo de inserção. 
• s → Deleta caractere e entra no modo de inserção. 
• S → Deleta linha e entra no modo de inserção. 
B. Sair do modo de edição 
• Pressionar a tecla <Esc>. 
 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 145 
 
C. Salvar e sair 
• :w → Salva as alterações. 
• :w arquivo → Salva as alterações no arquivo especificado. Funciona como “save as”. 
Continuará editando (e salvando) o arquivo com o nome anterior. 
• :sav arquivo → Salva as alterações no arquivo especificado. Funciona como “save as”. 
Continuará editando (e salvando) o arquivo com o novo nome. 
• :q → Sai. 
• :q! → Força a saída sem salvar as alterações. 
• :wq → Salva as alterações e sai. 
D. Movimentação 
A forma mais comum para movimentar o cursor ainda é por meio das setas do teclado, mas 
podem ser utilizadas também as teclas alfabéticas. 
• j → Baixo. 
• k → Cima. 
• l → Direita. 
• h → Esquerda. 
• 0 → Volta ao começo da linha (tecla zero). 
• ^ → Volta ao começo da linha (duas vezes já que se trata de um acento). 
• $ → Vai até o final da linha. 
• w → Avança até a próxima palavra. 
• e → Avança até o fim da palavra atual. 
• b → Retorna ao início da palavra. 
• f[caractere] → Pressione f seguido de algum caractere para posicionar o cursor na 
próxima ocorrência desse caractere. 
• t[caractere] → A mesma coisa para o f, mas posiciona um caractere antes do caractere 
pressionado. 
• gg → Retorna à primeira linha. 
• G → Vai até a última linha. 
• :[número da linha] → Vai até a linha especificada. 
• ´´ → Volta até onde você estava antes de pular de posição. 
E. Apagando 
Em modo de edição, utilize as teclas <Backspace> e <Delete> para as correções normais. 
Em modo de comando podem ser realizadas exclusões mais elaboradas. 
• x → Apaga o caractere sob o cursor. 
• X → Apaga o caractere antes do cursor. 
• D → Apaga da posição atual até o fim da linha. 
• J → Junta duas linhas. 5J juntará cinco linhas contíguas. 
• dd → Apaga toda a linha. 
• dj → Apaga 2 linhas abaixo. 
• dk → Apaga 2 linhas acima. 
• dw → Apaga até o fim da palavra. 
• dt" → Apaga da posição atual até o fechamento das aspas. 
• 5db → Apaga cinco palavras para trás. 
• d[algum comando de posicionamento] - Combina o comando com qualquer outro 
comando de posicionamento, veja os exemplos abaixo: 
 
Sistemas Operacionais 
Marcio Quirino - 146 
 
F. Desfazendo alterações 
• u → Desfazer. 
• ^r → Refazer. 
G. Copiando 
• yy → Copia toda a linha. 
• Y → Copia toda a linha. 
• yw → Copia até o fim da palavra. 
• y2j → Copia mais duas linhas abaixo. 
• "+y → Copia para a área de transferência. 
H. Colando 
• p → Cola a partir da posição atual. 
• P → Cola na posição atual. 
• [p → Colar antes. 
• ]p → Colar depois. 
• "+gp → Colar da área de transferência. 
I. Repetição de comandos 
Para repetir um comando,digite antes um número representando a quantidade de vezes que 
deseja repeti-lo. Exemplo: 
• 3w - Avança três palavras 
• 10k - Sobe dez linhas 
• 2t" - Coloca o cursor antes da segunda aspas 
• 3i[escreva e pressione a tecla <Esc>] → O que for digitado será inserido 3 vezes. 
J. Buscar 
• /txt → Busca pelo termo txt. Para ignorar a diferença entra maiúsculas e minúsculas, basta 
incluir \c no termo da busca: /\ctxt - Realiza uma busca do termo digitado sem diferenciar 
se está em maiúsculo ou minúsculo. /\Ctxt (C maiúsculo) força a diferenciação de 
maiúsculas e minúsculas. 
• n → Localiza a próxima ocorrência. 
• N → Localiza a ocorrência na direção contrária. 
• * → Localiza palavra sob o cursor. 
• :set hlsearch → Destaca todos os termos encontrados (highlight). 
• :set nohlsearch → Desabilita a funcionalidade. 
• :set ignorecase → Configura todas as buscas para não diferenciar maiúsculas e 
minúsculas. 
É possível utilizar expressões regulares como padrão de busca! 
Montagem de partições em Linux 
 
Para execução deste exemplo, utilizaremos as partições criadas e formatadas nos exemplos anteriores: 
Partição Tipo Tamanho 
/dev/sdb1 ext4 3 GB 
/dev/sdb2 NTFS 2 GB 
/dev/sdb3 ext4 1 GB 
 As partições estão criadas em um disco (/dev/sdb) de 10 GB. 
 No Microsoft Windows®, cada letra de unidade (C:, D:, E:) identifica um sistema de arquivos em uma partição 
de disco ou em um dispositivo, enquanto no Linux as partições são acessadas em diretórios, conhecidos como pontos 
de montagem, e que fazem parte da estrutura do sistema de arquivos raiz. 
Sistemas Operacionais 
Marcio Quirino - 147 
 
 Cada partição pode ser montada em qualquer diretório. 
 No caso de um sistema de arquivos cheio, pode-se copiar o conteúdo de um diretório para outro sistema de 
arquivos, apagar o conteúdo do diretório original e montar partição onde foram copiados os arquivos naquele local. 
 A adição de novas partições ou substituição de discos rígidos não afeta a ordem de identificação dos discos e 
pontos de montagem. 
 Montagem de sistema de arquivos 
 A montagem de um sistema de arquivos é feita por intermédio do comando mount, cuja sintaxe é: 
 mount [dispositivo] [ponto de montagem] [opções] 
 Sendo: 
• dispositivo → Identificação do dispositivo/partição que será montado. 
• ponto de montagem → Diretório de onde o dispositivo/partição será montado. 
 Algumas opções: 
• -t [tipo] → Tipo do sistema de arquivos utilizado (ext2, ext3, ext4, vfat, iso9660, etc.). 
• -r → Monta a partição como somente leitura. 
• -w → Monta a partição como leitura/gravação. É o padrão. 
 Desmontagem de sistema de arquivos 
 Para desmontar um sistema de arquivos utiliza-se o comando umount, cuja sintaxe é: 
 umount [dispositivo ou ponto de montagem] 
 Montando e desmontando sistemas de arquivos 
Para a montagem dos sistemas de arquivos criados anteriormente, utilizaremos os seguintes pontos de 
montagem: 
 Partição Ponto de montagem 
/dev/sdb1 /extra/b1 
/dev/sdb2 /extra/b2 
/dev/sdb3 /extra/b3 
 O primeiro passo é montar a estrutura de diretórios que será utilizada para a montagem dos sistemas de 
arquivos. Os comandos utilizados para a criação dos diretórios, que serão estuados adiante, são: 
sudo mkdir -p /extra/b1 
sudo mkdir /extra/b2 
sudo mkdir /extra/b3 
 Uma vez criados os pontos de montagem, basta utilizar o comando mount para montar as partições: 
sudo mount -t ext4 /dev/sdb1 /extra/b1 
sudo mount -t ntfs /dev/sdb2 /extra/b2 
sudo mount -t ext4 /dev/sdb3 /extra/b3 
 Neste momento, temos os sistemas de arquivos formatados e montados, prontos para utilização. 
 Uma forma de verificar os sistemas de arquivos montados e prontos para uso é por intermédio do comando “df 
-h”. Na listagem a seguir podemos ver o resultado do comando. Para facilitar a leitura, foram omitidos alguns sistemas 
de arquivos montados por padrão. 
fabio@ubuntu20:~$ df -h 
Sist. Arq. Tam. Usado Disp. Uso% Montado em 
Udev 967M 0 967M 0% 
/dev tmpfs 199M 1,4M 198M 1% /run 
/dev/sda5 15G 6,1G 7,4G 46% / 
/dev/sda1 511M 4,0K 511M 1% /boot/efi 
/dev/sdb1 2,9G 9,0M 2,8G 1% /extra/b1 
/dev/sdb2 2,0G 11M 2,0G 1% /extra/b2 
/dev/sdb3 976M 2,6M 907M 1% /extra/b3 
Sistemas Operacionais 
Marcio Quirino - 148 
 
 Para desmontar os sistemas de arquivos montados, utiliza-se o comando umount. 
sudo umount /dev/sdb1 
sudo umount /dev/sdb2 
sudo umount /dev/sdb3 
 Podemos verificar que os sistemas de arquivos foram desmontados executando novamente o comando “df -
h”. 
Montagem automática de sistemas de arquivos 
 O arquivo /etc/fstab permite que as partições do sistema sejam montadas facilmente, especificando somente 
o dispositivo ou o ponto de montagem. É possível também configurar para que os sistemas de arquivos sejam montados 
automaticamente durante o boot. Este arquivo contém parâmetros sobre as partições que são lidos pelo comando 
mount. 
Cada linha deste arquivo contém a partição a ser montada, o ponto de montagem, o sistema de arquivos 
utilizado pela partição e outras opções. O arquivo possui a seguinte estrutura: 
Sistema_de_arquivos Ponto_de_Montagem Tipo Opções dump ordem 
/dev/sda1 / ext4 defaults 0 1 
/dev/sda2 /home ext4 defaults 0 2 
/dev/sda3 /extra vfat defaults,noauto,rw 0 0 
/dev/sda4 none swap sw 0 0 
 Em que: 
• Sistema de Arquivos → Partição a ser montada. 
• Ponto de montagem → Diretório onde a partição será montada. 
• Tipo → Tipo de sistema de arquivos utilizado na partição que será montada. 
• Opções → Especifica as opções usadas com o sistema de arquivos. Algumas opções: 
o defaults → Utiliza valores padrões de montagem. 
o noauto → Não monta os sistemas de arquivos durante a inicialização. o ro → Monta como 
somente leitura. o user → Permite que usuários montem o sistema de arquivos. 
o sync → Faz com que os dados sejam gravados imediatamente na unidade. 
• dump → Especifica se será feito backup com utilitário dump, se estiver instalado. Podem ser colocados 
os valores 0 (desativa backup) ou 1 (ativa backup). 
• ordem → Define a ordem que os sistemas de arquivos serão verificados na inicialização do sistema. 
Se usar 0, o sistema de arquivos não é verificado. O primeiro sistema de arquivos que deverá ser 
verificado é o raiz. 
 Para o exemplo acima, após configurar o arquivo /etc/fstab, basta digitar o comando “mount /dev/sda3” ou 
“mount /extra” para que a partição “/dev/sda3” seja montada no ponto de montagem “/extra”. Não é necessário 
especificar o sistema de arquivos da partição, pois o mount verificará no arquivo /etc/fstab. 
Partição de swap (memória virtual) 
 A partição de swap é utilizada para oferecer o suporte à memória virtual, em adição à memória RAM do 
sistema. 
 Quando um processo começa a encher a memória RAM, o sistema operacional move automaticamente os 
dados que não estão sendo usados para a partição de swap e libera parte da memória RAM para continuar carregando 
os dados necessários. Quando os dados movidos para a partição de swap são solicitados, o sistema operacional os 
move da partição de swap de volta para a memória RAM. 
 Criando o swap em uma partição 
 No disco criado anteriormente (/dev/sdb), vamos utilizar o espaço restante para criar a partição /dev/sdb4, 
ocupando o restante do disco. Vamos ainda definir o tipo da partição como swap para que possa ser utilizada em 
adição à memória RAM do sistema. 
 Para criar a partição, utilize o fdisk executando-o em um terminal. Para isso, digite no shell o comando “sudo 
fdisk /dev/sdb”. Forneça a seguinte sequência de comandos: 
Sistemas Operacionais 
Marcio Quirino - 149 
 
 Comando Descrição 
n Cria partição 
p Tipo primária 
 Primeiro setor (embranco para valor padrão) 
 Último setor (em branco para utilizar todo o restante do disco) 
t Alterar o tipo da partição 
4 Selecionar a partição 4 para alteração do tipo 
L Verificar o código hexadecimal para partição de swap 
82 Identifica a partição como swap 
w Sai gravando as alterações 
 
Como ainda restavam 4 GB de espaço livre no disco, foi criada uma partição de 4GB do tipo Linux swap. 
 O programa usado para formatar uma partição de swap é o mkswap. Para criar uma partição de swap em 
“/dev/sdb4”, por exemplo, deve-se executar o comando “sudo mkswap /dev/sdb4”. 
A opção “-c” pode ser usada com o mkswap para verificar se existem clusters danificados na partição. 
Com a partição de swap formatada, o comando “sudo swapon /dev/sdb4” deve ser utilizado para ativar a 
partição de swap. 
O swapon ativa a partição de swap até a próxima reinicialização do sistema. Para ativar esta partição de swap 
para todas as seções, é necessário acrescentar no arquivo /etc/fstab uma linha como a abaixo: 
/dev/sdb4 none swap sw 0 0 
 Se utilizar mais do que uma partição de swap, pode ser útil o uso da opção “-p NUM”, que especifica a 
prioridade em que a partição de swap será usada. Partições com número maior serão usadas primeiro. Devem ser 
utilizados números maiores para partições mais rápidas e números menores para partições mais lentas. 
 Caso precise desativar a partição de swap, use o comando: “swapoff <partição>”. Para o nosso exemplo, o 
comando seria “sudo swapoff /dev/sdb4”. 
 Criando o swap em um arquivo 
 Também é possível criar um arquivo para ser utilizado como apoio à memória virtual. 
 Utilize o comando dd para criar um arquivo com o tamanho desejado. Os parâmetros do dd são: 
• if → Arquivo fonte de onde os dados serão copiados. 
• of → Arquivo destino para onde os dados serão copiados. 
• bs → Quantidade de dados a ser copiado por bloco. 
• count → Quantidade de blocos a ser copiado. 
Para criar o arquivo /troca com 512 MB contendo valores o (zero), executar o comando: 
sudo dd if=/dev/zero of=/troca bs=1024 count=524288 
 Após, executar o comando “sudo mkswap /troca” para formatar o arquivo. Feito isso, o sistema de arquivos 
swap estará criado e pronto para ser utilizado. 
 Ativar o arquivo de swap com o comando “sudo swapon /troca”. 
 Para conferir a qualquer momento se o tamanho da memória virtual foi modificado pode-se utilizar o comando 
“free”. 
 Podem ser usadas partições de swap e arquivos de swap ao mesmo tempo. 
 O swapon ativa o arquivo de swap até a próxima reinicialização do sistema. Para ativar este arquivo de swap 
para todas as seções, é necessário acrescentar no arquivo /etc/fstab uma linha como a abaixo: 
/troca none swap sw 0 0 
Sistemas Operacionais 
Marcio Quirino - 150 
 
 nano 
Assim como vim, o nano é também um editor de texto para linha de comando que está presente na 
grande maioria das distribuições Linux. Mas ao contrário do vim, é um editor que não possui diferentes 
modos de operação, sendo bem mais intuitiva sua utilização. 
O nano é executado a partir de um terminal digitando o comando “nano nome_do_arquivo”, no 
qual nome_do_arquivo é o nome do arquivo que será executado. O programa já inicia sua execução com o 
arquivo aberto para execução. 
 
Editor de texto nano executando em um terminal do Linux. 
Os principais comandos do nano ficam disponíveis de forma visual na parte inferior da tela. São eles: 
• <CTRL>+G → Obter ajuda; 
• <CTRL>+O → Salvar o arquivo; 
• <CTRL>+X → Sair; 
• <CTRL>+R → Abrir arquivo; 
• <CTRL>+W → Procurar no texto; 
• <CTRL>+\ → Pesquisar e substituir; 
• <CTRL>+K → Copia a linha para a memória e a apaga; 
• <CTRL>+U → Cola o que estiver na memória; 
• <CTRL>+J → Quebra a linha em várias linhas de forma a caberem na janela; 
• <CTRL>+C → Mostra uma linha indicando a posição em que se encontra no texto; 
• <CTRL>+L → Ir para a linha. 
Dica 
Consulte a lista de todos os comandos disponíveis abrindo o editor de textos nano e teclando <CTRL>+G. 
gedit 
É bom que o administrador de sistemas Linux tenha conhecimentos de utilização de editores de texto 
de linhas de comando, pois em uma emergência, em que não é possível utilizar o sistema pela interface 
Sistemas Operacionais 
Marcio Quirino - 151 
 
gráfica, ele poderá editar os arquivos de configuração do sistema sem maiores dificuldades. Porém, quando 
existe uma interface gráfica disponível para utilização, pode ser mais confortável a utilização de um editor 
de textos em modo gráfico. 
Como as distribuições Linux são livres para escolherem as interfaces gráficas que comporão o 
sistema, e cada uma possui seu próprio editor de textos puro, o editor utilizado na interface gráfica dependerá 
da interface utilizada. 
O Ubuntu 20.04 LTS, sistema operacional Linux aplicado em nossos exemplos, utiliza o GNOME 
como interface gráfica. O editor de textos puro do GNOME é conhecido como gedit e pode ser colocado em 
execução de diferentes formas. 
A primeira delas é navegando pelos arquivos utilizando o gerenciador de arquivos do GNOME e 
clicando duas vezes sobre o nome do arquivo. Se for um arquivo cujo formato esteja configurado para ser 
aberto no gedit, ele será colocado em execução. 
A segunda forma é abrindo a tela de aplicativos do GNOME e selecionando o gedit. Normalmente 
aparece com o nome “Editor de texto”. 
Uma terceira forma de abrir o gedit é por intermédio do shell. Abra um terminal, entre no diretório 
onde se encontra o arquivo que deseja editar e entre com o comando “gedit <nome_do_arquivo>” para que 
o arquivo seja aberto no gedit. Ou simplesmente digite gedit para iniciar o gedit. 
Na imagem a seguir podemos ver a tela do gedit com um arquivo em edição: 
 
Tela do gedit (editor padrão do GNOME). 
No canto superior esquerdo da tela (1) existe um botão “Abrir”. Ele pode ser utilizado para abrir um 
novo documento no gedit. 
Atenção 
Ao abrir um novo documento, o anterior também permanece em edição, sendo que a tela do gedit é dividida 
verticalmente para permitir a visualização de ambos. 
Sistemas Operacionais 
Marcio Quirino - 152 
 
À direita do botão, existe um triângulo invertido (2) que pode ser utilizado para buscar rapidamente 
os últimos arquivos que foram abertos no editor. Ainda próximo ao triângulo, existe um botão (3) utilizado 
quando se deseja criar um arquivo. 
No centro (4) aparece o nome do arquivo e edição, e o nome do diretório onde o arquivo se encontra. 
O botão “Salvar” (5) é utilizado para salvar o arquivo em edição a qualquer momento. 
À direita do botão “Salvar” (6) fica o botão para acesso ao menu do editor, onde existem várias 
opções e ferramentas, entre elas opções para localizar e imprimir. Abaixo na janela, na barra de status, é 
possível selecionar o tipo do arquivo em edição (7). 
Dica 
Normalmente, o gedit seleciona automaticamente o tipo do arquivo e utiliza-o para auxiliar o usuário na edição 
do arquivo. 
No exemplo, está sendo editado um arquivo em Linguagem C, então o gedit auxilia fazendo 
automaticamente as tabulações e colorindo as palavras reservadas por tipo. É possível também escolher a 
largura da tabulação (8) adicionada quando é pressionada a tecla “Tab”. À direita, é informada a posição do 
cursor (linha, coluna) e por fim é mostrado (10) se a entrada de dados está em modo de inserção ou 
de sobreposição. 
Considerações finais 
Acabamos de estudar o funcionamento dos sistemas de arquivos utilizados pelos sistemas 
operacionais modernos. Para isso, iniciamos nossa jornada entendo os conceitos de arquivos e diretórios, 
e como são as técnicas de implementação destes objetos pelos diferentes sistemas de arquivos. Além disso, 
vimos como um sistema de cache é importante para aumentar o desempenho de acesso. 
Após o estudo conceitual, observamos como administrar um sistema de arquivos no sistema 
operacionalLinux. Para tanto, compreendemos como é o funcionamento de um disco rígido e como 
particioná-lo. Após particionar e definir o tipo do sistema de arquivos, aprendemos a formatá-lo e fazer sua 
montagem sobre o sistema de arquivos raiz do sistema operacional. 
No entanto, não basta criar e montar o sistema de arquivos, é preciso também saber como gerenciá-
lo. Por conta disso, aprendemos diversos comando para gerenciamento de arquivos e diretórios no Linux, 
assim como criar links simbólicos e hardlinks. 
Por fim, conhecemos sobre os principais editores de texto puro utilizados pelo Linux. Uma percepção 
importante para que os administradores de sistemas Linux possam recuperar o sistema na eventualidade 
de uma falha grave. 
Referências 
ARCHLINUX. Partitioning. Consultado em meio eletrônico em 22 ago. 2020. 
DEITEL, H.M. Sistemas Operacionais. 3 ed. São Paulo: Pearson Prentice Hall, 2005. 
MACHADO, F. B. & MAIA, L. P. Arquitetura de Sistemas Operacionais. 5 ed. Rio de Janeiro: LTC, 
2013. 
NEMETH, E. et al. Manual Completo do Linux: Guia do Administrador. 2 ed. São Paulo: Pearson 
Prentice Hall, 2007. 
UBUNTU. Official Ubuntu Documentation. Consultado em meio eletrônico em 2 ago. 2020. 
SILBERSCHATZ, A. Fundamentos de Sistemas Operacionais. 9 ed. Rio de Janeiro: LTC, 2013. 
Sistemas Operacionais 
Marcio Quirino - 153 
 
SILBERSCHATZ, A. & GALVIN, P. B. Sistemas Operacionais – Conceitos. 5 ed. São Paulo: Prentice 
Hall, 2000. 
SILVA, G. M. Guia Foca GNU/Linux. In: Guia Foca. 
SOARES, L. F. G. Redes de Computadores – Das LANs, MANs e WANS às Redes ATM. 2 ed. Rio 
de Janeiro: Campus, 1995. 
TANENBAUM, A. S. & BOS, H. Sistemas Operacionais Modernos. 4 ed. São Paulo: Pearson 
Educacional do Brasil, 2016. 
TANENBAUM, A. S. & WOODHULL, A. S. Sistemas Operacionais – Projeto e Implementação. 3 ed. 
Porto Alegre: Bookman, 2008. 
TANENBAUM, A. S. Redes de Computadores. 5 ed. São Paulo: Pearson, 2011. 
TANENBAUM, A. S. Structured Computer Organization. 3 ed. Prentice Hall International, 1990. 
Página consultada: NBCGIB 
Explore+ 
Para saber mais sobre os assuntos tratados neste tema, pesquise: 
LVM (Logical Volume Manager — gerenciador de volume lógico) disponível em Archlinux; 
Tópicos: Listas de controle de acesso e Adicionando novos usuários do livro NEMETH, E. et al. 
Manual Completo do Linux: Guia do Administrador. 2 ed. São Paulo: Pearson Prentice Hall, 2007. 
Acesse os sites: 
Distrowatch. Sobre distribuições Linux; 
Libreoffice. Para mais detalhes sobre essa ferramenta. 
 
Sistemas Operacionais 
Marcio Quirino - 154 
 
Automatizando Tarefas no Linux 
Descrição 
Ferramentas para automatização de tarefas em um sistema operacional Linux, empregando a 
ferramenta CRON e programação SHELL SCRIPT. 
Propósito 
Conhecer ferramentas de automatização do Linux essenciais para tarefas do dia a dia em servidores 
e estações de trabalho permitirá que tarefas rotineiras de administração e gerência de sistemas Linux sejam 
realizadas de forma mais eficiente e eficaz. 
Preparação 
Para melhor aproveitamento do curso, recomendamos dispor de uma máquina Linux para treinar 
com os exemplos apresentados. Caso não disponha de um computador com o Linux instalado, há duas 
formas simples de obtê-lo, sem precisar reinstalar seu computador: 
Mais simples e rápido: No Windows 10, instale o “Linux Subsystem” (da própria Microsoft). Em 
seguida, na loja Microsoft Store, instale uma distribuição Linux. Sugestão: Ubuntu Linux. 
Mais avançado: Instale uma máquina virtual utilizando um Hypervisor como o Virtualbox ou o 
Microsoft Hyper-V. Em seguida, baixe o CD de instalação de uma distribuição, à sua escolha, e instale-o na 
máquina virtual. 
Introdução 
Imagine que você é o administrador de um servidor Linux, responsável por um importante serviço da 
empresa e, ao final de cada dia, um relatório sobre esse serviço deve ser enviado para os gestores. Para 
emitir esse relatório diário, são necessários alguns comandos e a contabilização de resultados. Em seguida, 
os números obtidos precisam ser digitados e enviados por e-mail. 
A situação acima é muito comum e faz parte do dia a dia de muitos administradores, com tarefas 
rotineiras e repetitivas. Mas o cenário também descreve uma condição de baixa eficiência do trabalho, já 
que exige um esforço manual para realizar uma tarefa recorrente. Pense em todo o tempo acumulado, ao 
longo de meses ou anos, para a realização de uma única e específica tarefa, repetidamente. Por fim, a 
pessoa responsável por essa tarefa deverá estar disponível nos dias e horários determinados, e sua 
ausência precisará ser suprida por outra pessoa, ou a tarefa não será realizada. 
Para cenários assim, existem ferramentas capazes de automatizar tarefas em sistemas operacionais, 
como o Linux. Neste curso, aprenderemos como programar SCRIPTS para realizar tarefas concatenando 
sequências de comandos. Aprenderemos, também, a utilizar o serviço CRON para agendar a execução 
automática de processos. 
1. Agendamentos, por meio da ferramenta CRON 
Conceitos 
A necessidade de automatizar a execução de processos não é nova, e ainda nos anos 1970, nas 
primeiras versões do sistema operacional UNIX, foi criada uma ferramenta específica para essa função, que 
recebeu o nome de CRON. 
De simples configuração, o CRON permite determinar dias e horários em que comandos serão 
executados, de forma automática e sem a intervenção de usuários. 
Sistemas Operacionais 
Marcio Quirino - 155 
 
Ferramenta multiusuário 
É importante entender que o CRON é uma ferramenta multiusuário. Na prática, isso significa que 
cada usuário no sistema operacional poderá ter sua configuração própria e independente dos demais 
usuários. 
No CRON, os processos são sempre executados pelo usuário a quem pertence a configuração. 
Por exemplo, considere duas configurações de CRON, aqui representadas com palavras: 
Exemplo 
– Usuário ‘root’ 
Executar todos os dias às 23h o comando: /usr/limpeza 
- Usuário ‘bob’ 
Executar todos os domingos às 9h o comando: /home/bob/relatorio_semanal 
O CRON se encarregará de executar, todos os dias, às 23h o comando ‘/usr/limpeza’. 
Esse comando será executado pelo usuário ‘root’ no sistema operacional. 
Da mesma forma, todos os domingos, às 9h, o comando ‘/home/bob/relatorio_semanal’ será executado pelo 
usuário ‘bob’, automaticamente, através do CRON. 
Atenção 
Lembre-se: Como o CRON é um serviço multiusuário, sempre considere qual usuário executará os comandos 
configurados. Esteja atento para as permissões que serão necessárias para cada comando ser executado com 
sucesso. 
Como configurar o cron de usuário 
crontab 
O ‘TAB’ se refere a tabelas. 
A configuração que cada usuário possui no CRON é chamada de CRONTAB. Para manipular uma 
CRONTAB, usaremos o comando com esse mesmo nome. 
Para editar o CRONTAB, é usado o comando: 
$ crontab -e 
Observação: 
Ao usar o comando ‘crontab’ pela primeira vez, poderá ser apresentada uma opção para escolha do editor de 
texto. 
Assim como em quase tudo no Linux, o CRONTAB também é um arquivo texto. 
Dica 
Escolha o editor com que se sinta mais confortável. Se não tiver certeza, prefira um editor mais simples como 
o ‘nano’. 
$ crontab -e 
no crontab for bob - using an empty one 
 
Select an editor. To change later, run 'select-editor'. 
1. /bin/nano <---- easiest 
2. /usr/bin/vim.basic 
3. /usr/bin/vim.tiny 
4. /bin/ed 
javascript:void(0)
Sistemas Operacionais 
Marcio Quirino - 156 
 
Quando terminar de editar o CRONTAB, você deverá salvá-lo. Se for o editor ‘nano’, use a 
combinação de teclas Crtl-X. 
Ao abrir o editor, o CRONTAB poderá estar preenchido com diversas informações e instruções que 
as distribuições Linux incluem para auxiliar os usuários. 
Regras e formatos do crontab 
Todas as linhas sem conteúdo são ignoradas pelo CRON. 
• Todas as linhas começadas com ‘#’ são tratadas como comentários e, portanto, ignoradas 
peloCRON. Em geral, os editores mostrarão essas linhas com cores destacadas para facilitar 
a visualização. 
• Cada tarefa será configurada em uma (e somente uma) linha, que deverá conter os campos 
requeridos pelo CRON. 
• Cada linha possui 6 ou mais campos de configuração, separados por espaços. 
• Os cinco primeiros campos de cada linha representarão as configurações de tempo, ou seja, 
quando cada tarefa deverá ser executada. 
• O sexto campo e os demais representam o comando que será executado pelo CRON, no dia 
e horário estabelecido. 
A. Minuto 
Número de 0 a 59, representando o minuto em que a tarefa será executada. 
B. Hora 
Número de 0 a 23, representando a hora em que a tarefa será executada. 
C. Dia do mês 
Número de 1 a 31, representando o dia do mês. 
D. Mês 
Número de 1 a 12 (1 – janeiro, 2 – fevereiro etc). Também são admitidas abreviações, em inglês, 
‘jan’, ‘feb’, ‘mar’... 
E. Dia da semana 
0 → domingo 
1 → segunda-feira 
2 → terça-feira... 
O dia da semana costuma causar confusão entre nativos da língua portuguesa, pois nesse idioma 
alguns dias da semana são numerais (segunda, terça, quarta...). Esteja atento para isso. 
O CRON também admite o uso da máscara ‘*’ para representar ‘qualquer valor’. 
Vejamos alguns exemplos: 
 
Sistemas Operacionais 
Marcio Quirino - 157 
 
O CRON executará ‘/bin/comando’ todos os dias, sempre às 17h30. 
30 17 10 * * /bin/comando 
O CRON executará ‘/bin/comando’ no dia 10 de todos os meses, às 17h30. 
30 17 * 12 * /bin/comando 
O CRON executará ‘/bin/comando’ todos os dias do mês de dezembro, às 17h30. 
30 17 * * 5 /bin/comando 
O CRON executará ‘/bin/comando’ nas sextas-feiras, às 17h30. 
30 17 10 3 * /bin/comando 
O CRON executará ‘/bin/comando’ no dia 10 de março, às 17h30. 
30 17 * 3 1 /bin/comando 
O CRON executará ‘/bin/comando’ todas as segundas-feiras do mês de março, às 17h30. 
O CRON também permite incluir mais de um valor por campo e criar agendamentos sofisticados. 
• Valores separados por vírgula: A execução será disparada quando qualquer um dos valores 
for atendido. 
• Valores separados por traço: Indica intervalo, e o comando será executado quando qualquer 
um dos valores no intervalo for atendido. 
0,15,30,45 * * * * /bin/comando 
Nesse exemplo, o comando será executado nos minutos 0, 15, 30 e 45, todas as horas do dia, 
todos os dias. 
0,15,30,45 0,12 * * * /bin/comando 
Ao incluir as horas 0 e 12, o comando será executado todos os dias em 8 horários: 
• 0h, 0h15, 0h30, 0h45, 12h, 12h15, 12h30 e 12h45. 
0,15,30,45 0,12 * * 1-5 /bin/comando 
O comando será executado nos horários do exemplo acima, porém somente de segunda a sexta-
feira (1-5). 
0,30 8-17 * * 1-5 /bin/comando 
O comando será executado nos minutos 0 e 30, das horas 8 a 17 e somente de segunda a sexta-
feira. Ex: 8h, 8h30, 9h, 9h30 .... 16h30, 17h e 17h30. 
Também é possível definir o período entre intervalos usando o caractere ‘/’. Por exemplo: 
0 */2 * * * /bin/comando 
O comando será executado no minuto 0 a cada duas horas (/2): 0h, 2h, 4h, 6h ... 22h. 
0/10 * * * * /bin/comando 
O comando será executado a cada 10 minutos: 0h, 0h10, 0h20.... 
Sistemas Operacionais 
Marcio Quirino - 158 
 
Exemplo de uma tarefa automática de backup 
Como vimos, os cinco primeiros campos de cada linha correspondem ao agendamento da execução. 
A partir do 6º campo você deve incluir o comando que será executado, com seus parâmetros, exatamente 
como faria em um terminal. 
O comando ‘tar -cfz /tmp/backup.tar.gz /home/bob’ cria um arquivo TAR comprimido, com todo o 
conteúdo do diretório /home/bob. O nome desse arquivo será backup.tar.gz e estará dento do diretório /tmp. 
É um tipo de comando muito usado para fazer o backup de diretórios de usuários ou de aplicações em geral. 
Se quisermos automatizar essa tarefa para que seja executada todos os dias às 20h, devemos incluir 
a linha abaixo no CRONTAB: 
0 20 * * * tar -cfz /tmp/backup.tar.gz /home/bob 
Lembre-se: o CRON é um serviço multiusuário. O usuário que for executar o comando ‘tar’ deverá 
ter, ao mesmo tempo, permissão para ler o conteúdo do diretório de origem (/home/bob) e permissão para 
escrever no diretório de destino (/tmp). 
Atenção 
Importante: Não use o comando ‘sudo’ dentro do CRONTAB. O comando ‘sudo’ é interativo e requer a digitação 
de senha, o que não será possível enquanto estiver sendo executado pelo CRON. Em vez de usar o ‘sudo’, configure 
o comando diretamente no CRONTAB do usuário ‘root’. 
A configuração de cron para o sistema 
Além das configurações individuais por usuário, o CRON também pode ter uma configuração global, 
para o todo o sistema. Em geral, esse tipo de configuração é usado para rotinas de serviços e processos do 
sistema. 
Exemplo 
Alguns exemplos: 
• Rotação periódica de arquivos de logs, apagando arquivos antigos. 
• Restart automático de processos que necessitem desse tipo de operação. 
• Verificação de atualizações disponíveis e notificação. 
• Verificação de dispositivos de hardware e notificação dos problemas encontrados. 
O arquivo usado é o /etc/crontab. Como ele define uma configuração para todo o sistema, seu 
formato exige um campo a mais em cada linha, que é a indicação do usuário que executará cada comando. 
30 10 * * * root /bin/comando 
No exemplo acima, a indicação de que o CRON deverá executar o comando como o usuário ‘root’. 
As principais distribuições Linux trazem a configuração global com uma organização prática, já que 
rotinas poderão ser incluídas e excluídas à medida que serviços são instalados e desinstalados no servidor. 
Para que o arquivo /etc/crontab não precise ser alterado, é costume criar diretórios para as rotinas 
diárias, semanais e mensais. Em cada diretório serão criados programas (scripts) para cada uma das tarefas 
definidas. 
E no arquivo principal, /etc/crontab, é configurada a execução de todos os SCRIPTS em cada um 
dos diretórios, nos horários agendados. 
Esses diretórios costumam ter os nomes como abaixo: 
• /etc/cron.hourly → Rotinas de hora em hora. 
• /etc/cron.daily → Rotinas diárias. 
Sistemas Operacionais 
Marcio Quirino - 159 
 
• /etc/cron.weekly → Rotinas semanais. 
• /etc/cron.monthly → Rotinas mensais. 
Para exercitar: Procure esses diretórios na sua máquina Linux e veja os seus conteúdos. 
2. SCRIPTS para a automatização de tarefas no terminal 
Linux 
Conceitos 
Uma das características do terminal (SHELL) de comandos dos sistemas baseados no Unix, incluindo 
o Linux, é a possibilidade de desenvolvimento de lógicas avançadas por meio de SCRIPTS. 
Os SCRIPTS são arquivos-texto com sequências de comandos a serem executados pelo SHELL. 
Comentário 
Por serem lidos e interpretados diretamente pelo SHELL, não há necessidade de um processo de compilação 
como em diversas linguagens de programação. Após escritos, os arquivos contendo os SCRIPTS podem ser 
executados imediatamente. 
O SHELL do Linux permite a criação de variáveis de ambiente e possui comandos para comparação 
e operação de valores, além de estruturas de repetição. Combinando esses recursos, podemos automatizar 
tarefas complexas. 
Os SCRIPTS mais simples são aqueles que simplesmente executam diversos comandos em 
sequência, economizando nosso tempo. Os mais complexos podem analisar os resultados dos comandos e 
tomar decisões para os comandos seguintes, executando a tarefa com segurança, integridade e eficiência. 
O interpretador de shell 
Existem diversos interpretadores disponíveis para o Linux, e as sintaxes para SCRIPTS variam entre 
eles. Atualmente, as principais distribuições adotam o interpretador BASH como o padrão, portanto vamos 
utilizá-lo como referência nesse curso. 
A palavra mágica que identifica um script 
O Linux nos permite executar um SCRIPT da mesma forma que executamos um comando ou 
programa qualquer, mas isso tem uma implicação: Precisamos informar que o conteúdo daquele arquivo é 
um SCRIPT e não um arquivo qualquer.Para isso, todo SCRIPT deve ser iniciado com uma palavra mágica, composta por dois caracteres 
‘#!’ seguidos do caminho para o interpretador de SHELL. 
#!/bin/bash 
Neste exemplo estamos declarando que o arquivo é um SCRIPT e deverá ser interpretado pelo 
BASH, sendo /bin/bash o caminho completo para esse programa interpretador. 
Um script muito simples 
Vamos fazer um SCRIPT muito simples, contendo apenas um comando. O nome desse SCRIPT será 
‘script1’ e criaremos em nosso diretório HOME. 
Para começar, abrimos um editor de texto comum, como o ‘vi’ ou ‘nano’. 
$ nano script1 
Dentro do arquivo vamos incluir apenas duas linhas: 
Sistemas Operacionais 
Marcio Quirino - 160 
 
 
1. A palavra mágica. 
2. O comando ‘date’, que apenas retornará a data e hora atual. 
#!/bin/bash 
date 
Já percebemos que esse exemplo é um SCRIPT muito simples, sem grande utilidade, já que terá o 
mesmo efeito de simplesmente digitarmos o comando ‘date’. Mas o objetivo agora é rodar o nosso primeiro 
SCRIPT. 
Salve o arquivo e saia do editor. Se estiver usando o ‘nano’, use Ctrl-X, confirme que deseja salvar 
o arquivo e escolha o nome (‘script1’). 
Se agora usarmos o comando ‘ls’ para ver o conteúdo do diretório, encontraremos o nosso ‘script1’ 
entre os arquivos. Porém, se tentarmos digitar ‘script1’ no PROMPT, receberemos um erro do tipo “comando 
não encontrado”. 
Há duas questões que ainda precisam ser tratadas: 
1. A primeira delas é que criamos um arquivo texto, mas em momento algum autorizamos que 
ele seja executado, e essa é uma característica de segurança importante do Linux. 
Não basta criar um arquivo texto para que ele se comporte como um programa, é necessário 
dar permissão de execução para ele. 
Para dar essa permissão, usaremos o comando ‘chmod’. 
$ chmod u+x script1 
Nesse exemplo, concederemos a permissão de execução para o proprietário (OWNER) do 
arquivo. Caso deseje-se que qualquer usuário possa executá-lo, podemos usar o parâmetro 
‘a+x’. 
Ao usar o comando ‘ls -l’, veremos que a permissão foi concedida: 
-rwxr--r-- 1 bob bob 17 Sep 14 14:50 script1 
Se tentarmos executar o comando agora, ainda receberemos um erro, o que nos leva à segunda 
questão, outro mecanismo de proteção do Linux: Apenas programas em alguns diretórios do sistema podem 
ser executados sem a necessidade de indicar o seu caminho. 
2. Como o SCRIPT foi criado no HOME e esse não é um dos diretórios permitidos, precisaremos 
indicar o caminho, que pode ser utilizando o caminho absoluto ou relativo. 
Para executar o ‘script1’ que está no diretório atual, vamos empregar o caminho relativo, com 
o comando abaixo: 
./script1 
Onde ./ é um caminho que significa ‘o diretório atual’. 
Ao executar o SCRIPT teremos no terminal a saída do comando ‘date’, como esperávamos. 
$ ./script1 
Mon Sep 14 16:29:45 -03 2020 
Linhas em branco e comentários 
Você sabia 
As linhas sem conteúdo e as iniciadas com ‘#’ são ignoradas pelo interpretador. 
Sistemas Operacionais 
Marcio Quirino - 161 
 
As linhas iniciadas com ‘#’ podem ser usadas para comentários, observações e instruções sobre o SCRIPT. 
Não confunda com a palavra mágica na primeira linha: Ela começa com ‘#’ e é importante. 
Incluindo textos na resposta do script 
Nosso primeiro objetivo foi atingido: Criar um SCRIPT simples e executá-lo. O próximo passo é 
evoluir esse SCRIPT e mudar seu comportamento. 
Nesse exemplo, vamos mudar a saída para indicar somente a hora e com um texto mais amigável. 
Desejamos que a saída seja assim quando o SCRIPT for executado: 
Hora certa 12:30 
Para fazer essa mudança, precisamos: 
1. Inserir um comando para exibir o texto “Hora certa: “ 
2. Modificar o comando ‘date’ para mostrar a hora no formato HH:MM (onde HH é a hora com 
dois dígitos e MM o minuto, também com dois dígitos). 
A mudança no ‘date’ é fácil. Consultando a MANPAGE do comando, vemos que é possível determinar 
a saída passando o formato desejado como argumento: 
$ date +%H:%M 
Saiba Mais 
(%H será substituído pela hora e %M pelo minuto. Para mais formatos, consulte a MANPAGE do comando 
‘date’). 
O texto pode ser inserido usando-se o comando ‘echo’. Vamos mudar o SCRIPT para: 
#!/bin/bash 
echo "Hora certa" 
date +%H:%M 
O comando ‘echo’ envia para a saída padrão (stdout) o texto passado como parâmetro. 
Ao executar, teremos como saída: 
$ ./script1 
Hora certa 
12:30 
As informações que desejamos já estão presentes, porém em linhas diferentes. Isso ocorre porque 
o comando ‘echo’ insere uma quebra de linha após o texto. É possível inibir a quebra de linha passando o 
parâmetro ‘-n’ para o comando ‘echo’. Porém, vamos adaptar o SCRIPT colocando tudo no mesmo ‘echo’. 
#!/bin/bash 
echo "Hora certa $(date +%H:%M)” 
Quando colocamos o comando entre ‘$(‘ e ‘)’ estamos dizendo ao ‘echo’: Execute esse comando e 
envie o resultado junto ao texto para a saída. Então, ao executarmos o script, teremos: 
$ ./script1 
Hora certa 12:30 
Evoluindo o nosso SCRIPT para informar a data e hora: 
#!/bin/bash 
echo "Data: $(date +%d/%m/%Y) Hora: $(date +%H:%M)" 
Ao executar, teremos a resposta: 
$ ./script1 
Data: 15/09/2020 Hora: 16:44 
Sistemas Operacionais 
Marcio Quirino - 162 
 
Repare nesse último exemplo que o comando ‘date’ foi executado duas vezes dentro do ‘echo’. 
Inserindo caracteres especiais no comando ‘echo’ 
O comando ‘echo -e’ permite o uso de caracteres especiais. Por exemplo, para adicionar uma quebra 
de linha, pode ser usada a combinação ‘\n’. 
Ainda no nosso SCRIPT anterior: 
#!/bin/bash 
echo -e "Data: $(date +%d/%m/%Y)\nHora: $(date +%H:%M)" 
Ao executar, teremos a resposta: 
$ ./script1 
Data: 15/09/2020 
Hora: 16:44 
Criando pausas na execução de um script 
Em muitas situações, pode ser interessante, ou necessário, incluir pausas na execução de um 
SCRIPT. O comando ‘sleep’ permite realizar uma pausa com tempo configurável. 
Vamos criar o arquivo ‘script2’ para essa demonstração: 
#!/bin/bash 
date +%T 
sleep 1 
date +%T 
sleep 2 
date +%T 
sleep 3 
date +%T 
No ‘script2’ o comando ‘date’ é executado 4 vezes. Entre eles foi usado o comando ‘sleep’ com 
diferentes tempos. O número passado como parâmetro ao ‘sleep’ corresponde ao tempo, em segundos, de 
pausa. 
Lembrando: Para executar o ‘script2’, é necessário conceder permissão de execução. 
$ chmod u+x script2 
Ao executá-lo, obtemos: 
$ ./script2 
13:05:29 
13:05:30 
13:05:32 
13:05:35 
Repare, na indicação dos segundos, os intervalos do comando ‘sleep’, como programado. 
 
Em muitos casos, pode ser interessante aguardar uma interação do usuário. O comando ‘read’ 
suspende a execução do SCRIPT até que o usuário tecle ENTER. 
Substituindo no SCRIPT os comandos ‘sleep’ por ‘read’. 
#!/bin/bash 
Sistemas Operacionais 
Marcio Quirino - 163 
 
date +%T 
read 
date +%T 
read 
date +%T 
read 
date +%T 
O SCRIPT aguardará que o usuário digite ENTER após executar cada comando ‘date’. Comparando-
se as horas, será possível saber quanto tempo o SCRIPT aguardou por cada interação do usuário. 
$ ./script2 
13:09:12 
13:09:14 
13:09:16 
13:09:18 
As linhas em branco foram inseridas pela resposta do comando ‘read’ ao ENTER do usuário. 
Dica 
Experimente incluir o parâmetro ‘-s’ nos comandos ‘read’ para que as linhas em branco não apareçam. 
Apagando todo o conteúdo do terminal 
Às vezes, pode ser interessante apagar todo o conteúdo do terminal no início ou durante a execução 
de um SCRIPT, facilitando a visualização das respostas. Para isso, podemos usar o comando ‘clear’. 
Modificando o SCRIPT anterior, foi incluído um comando ‘clear’ no início do arquivo: 
#!/bin/bash 
clear 
date +%T 
read 
date +%T 
read 
date +%T 
read 
date +%T 
O resultado será igual ao anterior, porém o terminal estará limpo e a resposta começará na primeira 
linha. 
Terminando um script com valor de retorno 
Uma característica de processos no Linux é que eles terminam retornando um valornumérico para 
o sistema operacional, chamado de “return value” e que serve para indicar o sucesso da execução ou a 
ocorrência de erros. 
Comentário 
O valor de retorno pode ser de 0 a 255, e a regra geral é de que um valor de retorno 0 indica execução com 
sucesso. Os demais valores, de 1 a 255, podem ser usados para indicar o tipo de erro durante a execução. 
O comando ‘exit’ permite terminar o SCRIPT retornando um valor. 
Por exemplo, se um SCRIPT contiver a linha abaixo: 
exit 1 
Quando o ‘exit’ for executado, o SCRIPT será imediatamente encerrado e com valor de retorno igual 
a ‘1’. 
Se o comando ‘exit’ for executado sem o parâmetro de valor, ele retornará o resultado do último 
comando no SCRIPT. Isso também vale para um SCRIPT que não termina através do comando ‘exit’. 
Sistemas Operacionais 
Marcio Quirino - 164 
 
3. Variáveis de ambiente e estruturas de decisão em 
SCRIPTS 
Conceitos 
Assim como nas linguagens de programação, o terminal BASH também permite a criação de 
variáveis em seu ambiente. 
Comentário 
As variáveis são, de modo simplificado, um espaço para o armazenamento de informações. 
Utilizando variáveis podemos compartilhar dados entre vários comandos e tomar decisões para 
desviar o fluxo de execução do SCRIPT. 
Toda variável possui: 
A. Nome 
O nome de uma variável é a chave pela qual faremos referência a ela. 
B. Valor 
O valor é a informação armazenada. 
Atribuição de valores a uma variável 
Para declarar uma variável, atribuindo valor a ela, usamos a sintaxe abaixo: 
VAR=1 
Nesse exemplo, declaramos uma variável com o nome “VAR” e a ela foi atribuído o valor “1”. Se a 
variável VAR já existir, o valor anterior será perdido e substituído pelo novo. 
Atenção 
Na atribuição acima não deve haver espaços antes ou depois do sinal de igualdade, o que faria o terminal 
interpretar como a tentativa de executar o comando ‘VAR’ ou ‘VAR=’ 
Para atribuir textos com espaços, é necessário o uso de aspas: 
VAR=”Terminal do Linux” 
O nome da variável é sempre case-sensitive, ou seja, o terminal distingue caracteres maiúsculos e 
minúsculos no nome das variáveis. 
Referenciando variáveis 
Para fazer referência a uma variável, e obter o seu conteúdo, é necessário usar o símbolo $ à 
esquerda do nome. Se a variável se chama VAR, faremos referência a ela como $VAR. 
Por exemplo, experimente usar esses comandos no seu terminal: 
VAR=”Terminal do Linux” 
echo “$VAR” 
A saída do comando ‘echo’ será a frase “Terminal do Linux”. O ‘echo’ substituiu a referência $VAR 
pelo conteúdo da variável. 
 
 
Sistemas Operacionais 
Marcio Quirino - 165 
 
Atenção 1 
A variável só é utilizada sem o prefixo $ quando estamos atribuindo valor a ela. Para fazer referência, o $ 
sempre é necessário. 
Atenção 2 
No terminal BASH, ao contrário da maioria das linguagens de programação, as variáveis não possuem tipo. 
Portanto, a interpretação do conteúdo como número ou texto vai depender do contexto da operação que está sendo 
realizada. 
Atribuição da saída de um comando a uma variável 
Suponha que você está desenvolvendo um SCRIPT no qual a informação retornada por um comando 
será utilizada posteriormente. Uma das formas de você armazenar essa informação temporariamente é por 
meio de variáveis. 
No exemplo abaixo, simulamos um SCRIPT cuja execução é demorada. Para que o usuário saiba 
quanto tempo a execução demorou, esse SCRIPT apresentará no final os horários em que começou e o 
atual. 
No início da execução, o horário será salvo em uma variável de nome “INICIO”. 
#!/bin/bash 
INICIO=$(date +%T) 
 
echo "Executando uma tarefa demorada" 
sleep 5 
 
echo "Início: $INICIO / Término: $(date +%T)" 
exit 0 
Comentário 
Repare na segunda linha que o comando ‘date’ é executado, retornando a hora naquele momento, que será 
armazenada na variável INICIO. O comando ‘sleep 5’ simula uma tarefa demorada, aqui com 5 segundos de duração. 
Ao término da execução teremos os dois horários, o que nos permitirá saber quanto tempo o SCRIPT 
levou para executar: 
./script3> 
Executando uma tarefa demorada 
Início: 17:47:00 / Término: 17:47:05 
Atenção 
O conteúdo de variáveis é armazenado em memória, e serve muito bem para quantidades pequenas de dados. 
Se precisar guardar um volume grande, prefira utilizar arquivos temporários. 
Passando parâmetros para o script 
O terminal do Linux permite que um SCRIPT seja executado com parâmetros. Assim, podemos 
passar valores para o SCRIPT a cada execução, sem precisar modificar o seu conteúdo. 
Suponha um SCRIPT sendo executado com o comando abaixo, onde foram passados 4 parâmetros 
(lembre-se: Os parâmetros são separados pelo espaço). 
$ ./ script4 valor1 valor2 valor3 valor4 
Cada um dos parâmetros pode ser lido pelo SCRIPT consultando as variáveis $1, $2, $3 e $4, 
respectivamente. A variável $0 é o nome do próprio SCRIPT que foi executado. 
Considere o ‘script4’: 
Sistemas Operacionais 
Marcio Quirino - 166 
 
#!/bin/bash 
echo "Nome do script: $0" 
echo "Parametro 1: $1" 
echo "Parametro 2: $2" 
echo "Parametro 3: $3" 
echo "Parametro 4: $4" 
Esse SCRIPT irá buscar os 4 primeiros parâmetros e os exibirá. Os parâmetros que não forem 
preenchidos serão vistos como vazio pelo SCRIPT. 
Ao executar o SCRIPT, teremos a saída (não esqueça de conceder permissão de execução): 
$ ./script4 valor1 valor2 valor3 valor4 
Nome do script: ./script4 
Parametro 1: valor1 
Parametro 2: valor2 
Parametro 3: valor3 
Parametro 4: valor4 
Atenção 
Para parâmetros acima do número 10 a referência deve ser feita assim: 
${10}, ${11}, ${12} ... 
O operador lógico if 
Assim como quase todas as linguagens de programação, o BASH também permite comparações por 
meio do comando ‘if’. 
O comando recebe uma expressão para ser avaliada, e seu retorno dependerá do resultado da 
avaliação. 
A sintaxe básica é a seguinte: 
if [ CONDIÇÃO ] 
then 
# Alguma tarefa # 
fi 
O comando ‘if’ avalia a condição apresentada. 
A. Verdadeiro 
Se o resultado for verdadeiro, ele executará o código entre ‘then’ e ‘fi’, nesse exemplo 
representado pela frase “# Alguma tarefa #”. 
B. Falso 
Se o resultado for falso, o fluxo da execução é desviado para depois do ‘fi’, portanto os comandos 
em “# Alguma tarefa #” não são executados. 
O operador ‘if’ também permite o uso da declaração ‘else’, que será executada sempre que o 
resultado da condição for falso. 
if [ CONDIÇÃO ] 
then 
# Alguma tarefa executada se a condição for verdadeira # 
else 
# Alguma tarefa executada se a condição for falsa # 
fi 
Comparadores numéricos 
Observe os comparadores numéricos 
Sistemas Operacionais 
Marcio Quirino - 167 
 
A. IGUALDADE ( -EQ → IS EQUAL ) 
if [[ “$A” -eq “$B” ]] 
Resulta verdadeiro se o valor da variável $A for igual ao da variável $B. 
B. DIFERENTE ( -NE → IS NOT EQUAL ) 
if [[ “$A” -ne “$B” ]] 
Resulta verdadeiro se o valor da variável $A for diferente do da variável $B. 
C. MAIOR QUE ( -GT → IS GREATER THAN ) 
if [[ “$A” -gt “$B” ]] 
Resulta verdadeiro se o valor da variável $A for maior que o valor da variável $B. 
D. MAIOR OU IGUAL ( -GE → IS GREATER THAN OR EQUAL ) 
if [[ “$A” -ge “$B” ]] 
Resulta verdadeiro se o valor da variável $A for maior que o valor da variável $B ou igual. 
E. MENOR QUE ( -LT → LESS THAN ) 
if [[ “$A” -lt “$B” ]] 
Resulta verdadeiro se o valor da variável $A for menor que o valor da variável $B. 
F. MENOR OU IGUAL ( -LE → IS LESS THAN OR EQUAL) 
if [[ “$A” -le “$B” ]] 
Resulta verdadeiro se o valor da variável $A for menor que o valor da variável $B ou igual. 
Para exemplificar, considere esse ‘script5’ que recebe dois valores como parâmetros e realiza uma 
série de comparações: 
#!/bin/bash 
 
A=$1 
B=$2 
 
if [[ "$A" -eq "$B" ]] 
then 
echo "A e B são iguais" 
fi 
 
if [[ "$A" -ne "$B" ]] 
then 
echo "A e B são diferentes" 
fi 
 
if [[ "$A" -gt "$B" ]] 
then 
echo "A é maior que B" 
fi 
 
if [[ "$A" -lt "$B" ]]then 
echo "A é menor que B" 
fi 
O primeiro parâmetro ($1) é atribuído como o valor da variável $A, e o segundo como o valor da 
variável $B. 
Sistemas Operacionais 
Marcio Quirino - 168 
 
Ao executarmos, a saída dependerá dos valores passados: 
$ ./script5 10 5 
A e B são diferentes 
A é maior que B 
 
$ ./script5 10 20 
A e B são diferentes 
A é menor que B 
 
$ ./script5 10 10 
A e B são iguais 
Comparadores de cadeias de caracteres (strings) 
Observe agora os comparadores de cadeias de caracteres: 
A. IGUALDADE 
if [[ “$A” = “$B” ]] 
Resulta verdadeiro se o valor (texto) da variável $A for igual ao da variável $B. 
B. DIFERENTE 
if [[ “$A” != “$B” ]] 
Resulta verdadeiro se o valor (texto) da variável $A for diferente do da variável $B. 
C. CADEIA NULA (NULL) OU VAZIA 
if [[ -z “$A” ]] 
Resulta verdadeiro se o valor (texto) da variável $A tiver zero caracteres (tamanho zero). 
D. CADEIA NÃO NULA (NOT NULL) 
if [[ -n “$A” ]] 
Resulta verdadeiro se o valor (texto) da variável $A tiver tamanho maior do que zero. 
Comentário 
O SCRIPT que desenvolvemos no exemplo anterior possui uma falha: Se for executado sem parâmetros vai 
retornar erro, pois tentará comparar valores ($1 e $2) que não existem. 
Esse problema pode ser facilmente resolvido incluindo-se um teste de validade dos parâmetros no 
início da execução. 
#!/bin/bash 
 
# Atribuir os parâmetros como as variáveis A e B 
A=$1 
B=$2 
 
# Teste de validade dos parâmetros. Se algum deles for nulo 
# o SCRIPT aborta a execução e retorna valor 1 para indicar 
# que ocorreu uma falha. 
# Testa se o primeiro valor é válido. 
if [[ -n "$A" ]] 
then 
echo "O primeiro valor é válido: $A" 
else 
echo "O primeiro valor é nulo" 
exit 1 
fi 
 
Sistemas Operacionais 
Marcio Quirino - 169 
 
# Testa se o segundo valor é válido. 
if [[ -n "$B" ]] 
then 
echo "O segundo valor é válido: $B" 
else 
echo "O segundo valor é nulo" 
exit 1 
fi 
 
# Inicia as comparações entre $A e $B 
if [[ "$A" -eq "$B" ]] 
then 
echo "A e B são iguais" 
fi 
 
if [[ "$A" -ne "$B" ]] 
then 
echo "A e B são diferentes" 
f1 
 
if [[ "$A" -gt "$B" ]] 
then 
echo "A é maior que B" 
fi 
 
if [[ "$A" -lt "$B" ]] 
then 
echo "A é menor que B" 
fi 
 
exit 0 
Se tentarmos executar o SCRIPT sem preencher ambos os parâmetros, o erro do usuário será 
detectado e indicado. 
$ ./script5 
O primeiro valor é nulo 
 
$ ./script5 22 
O primeiro valor é valido: 22 
O segundo valor é nulo 
Executando o script sem parâmetros 
No último exemplo criamos um SCRIPT para comparar dois valores passados por meio de 
parâmetros na linha de comando. Em algumas situações, porém, pode ser mais prático e intuitivo pedir que 
o usuário digite os valores durante a execução. 
Esse tipo de SCRIPT é chamado de INTERATIVO, pois exige a interação de um usuário. 
O comando ‘read’, que usamos no módulo anterior para aguardar uma interação do usuário, também 
pode ser usado para receber um valor e atribuí-lo a uma variável. 
$ read A 
Irá aguardar o usuário digitar alguma informação, e terminar com ENTER. A informação digitada será 
atribuída à variável A. 
$ read A 
Mensagem → Texto digitado pelo usuário 
$ echo “$A” 
Mensagem 
Vamos criar uma versão interativa do exemplo que executamos anteriormente. Nessa versão, 
apenas o começo do SCRIPT será modificado – em vez de receber A e B por parâmetros, eles serão obtidos 
do usuário pelo comando ‘read’. 
Sistemas Operacionais 
Marcio Quirino - 170 
 
#!/bin/bash 
# Pedir ao usuário a digitação dos valores 
# O parâmetro '-n' no echo faz com que ele não insira uma quebra de linha apos o texto 
echo -n "Digite o primeiro valor: " 
read A 
echo -n "Digite o segundo valor: " 
read B 
 
### O RESTANTE DO SCRIPT É IGUAL AO script5 
# Teste de validade dos parâmetros. Se algum deles for nulo 
# o SCRIPT aborta a execução e retorna valor 1 para indicar 
# que ocorreu uma falha. 
# Testa se o primeiro valor é nulo. 
if [[ -n "$A" ]] 
then 
echo "O primeiro valor é valido: $A" 
else 
echo "O primeiro valor é nulo" 
exit 1 
fi 
 
# Testa se o segundo valor é nulo. 
if [[ -n "$B" ]] 
then 
echo "O segundo valor é válido: $B" 
else 
echo "O segundo valor é nulo" 
exit 1 
fi 
 
# Inicia as comparações entre $A e $B 
if [[ "$A" -eq "$B" ]] 
then 
echo "A e B são iguais" 
fi 
 
if [[ "$A" -ne "$B" ]] 
then 
echo "A e B são diferentes" 
fi 
 
if [[ "$A" -gt "$B" ]] 
then 
echo "A é maior que B" 
fi 
 
if [[ "$A" -lt "$B" ]] 
then 
echo "A é menor que B" 
fi 
 
exit 0 
Realizando operações aritméticas em script 
Operações aritméticas com variáveis são muito úteis em SCRIPTS. Podem ser usadas para cálculos 
comuns e até controle em estruturas de repetição. 
Como um primeiro exemplo, observe o ‘script6’ que solicitará dois valores e retornará a soma deles: 
#!/bin/bash 
# Pede a digitação dos valores e os armazena nas 
# variáveis A e B 
 
 
echo -n "Digite o primeiro valor (A): " 
read A 
echo -n "Digite o segundo valor (B): " 
Sistemas Operacionais 
Marcio Quirino - 171 
 
read B 
 
 
# Calcula A+B e atribui o resultado na variável C 
(( C=A+B )) 
 
# Exibe o resultado 
echo "O resultado de A+B = $C" 
 
# Exibe o mesmo resultado, porém indicando o cálculo 
# no echo, sem a necessidade da variável C. 
echo "O resultado de A+B = $(( A+B ))" 
 
exit 0 
 
Ao executar o comando (informando A=12 e B=15), temos: 
$ ./script6 
Digite o primeiro valor (A): 12 
Digite o segundo valor (B): 15 
O resultado de A+B = 27 
O resultado de A+B = 27 
Atenção 
O cálculo foi realizado de duas formas. Na primeira, o resultado foi atribuído a uma variável (C). Na segunda 
forma, o cálculo foi feito diretamente a partir do comando ‘echo’. 
Incrementando variáveis 
Em estruturas de repetição, precisamos de variáveis auxiliares, que são constantemente 
incrementadas. O incremento de uma variável X pode ser feito com: 
(( X++ )) 
Exemplo: 
$ X=1 
 
$ echo $X 
1 
 
$ (( X++ )) 
 
$ echo $X 
2 
Atenção 
No exemplo acima, com comandos digitados diretamente no SHELL, o primeiro declara a variável X e atribui o 
valor ‘1’ a ela. Confirmamos que o valor foi atribuído no segundo comando (‘echo’), mostrando o valor de X. No terceiro 
comando, incrementamos o valor de X em uma unidade, o que nos é comprovado pelo último comando (‘echo’). 
Operações com ponto flutuante 
Uma desvantagem do SHELL é que ele não realiza operações com ponto flutuante. Se tentarmos 
uma divisão, por exemplo, o resultado será sempre um inteiro, perdendo-se as casas decimais. 
Um comando que pode nos auxiliar é o ‘bc’ (consulte a MANPAGE para maiores informações). No 
exemplo abaixo, o comando é invocado recebendo de um ‘echo’ a expressão para ser calculada. 
$ echo "scale=5; 29/3" | bc -l 
9.66666 
A expressão tem duas partes, separadas por ponto e vírgula. A primeira parte (scale=5) define 
quantas casas decimais deverá ter a resposta. A segunda parte é o cálculo, nesse caso 29 dividido por 3. 
Sistemas Operacionais 
Marcio Quirino - 172 
 
Considere o ‘script7’ abaixo, que pede ao usuário três números (A, B e C) e calcula sua média. 
#!/bin/bash 
 
echo -n "Digite o primeiro valor (A): " 
read A 
echo -n "Digite o segundo valor (B): " 
read B 
echo -n "Digite o terceiro valor (C): " 
read C 
 
MEDIA=$(echo "scale=2;($A+$B+$C)/3" | bc) 
 
echo “A média dos três valores é: $MEDIA” 
exit 0 
 
Ao executar o SCRIPT: 
$ ./script7 
Digite o primeiro valor (A): 10 
Digite o segundo valor (B): 9 
Digite o terceiro valor (C): 8.5 
A média dos três valores é: 9.16 
Repare que o comando ‘bc’ realizou o cálculo utilizando ponto flutuante, sem perder as casas 
decimais no resultado. 
4. Tarefas complexas em SCRIPTS com o uso de estruturas 
de repetição 
 
 
Conceitos 
Estruturas de repetição, também chamadas de LOOPS, são recursos fundamentais em qualquer 
modelo de programação. Através

Mais conteúdos dessa disciplina