Anda di halaman 1dari 247

Sistemas Operacionais

Celso Maciel da Costa

Sumrio

1. Evoluo e Funcionamento dos Sistemas Operacionais Evoluo dos Sistemas Operacionais. Estrutura e funcionamento dos Sistemas Operacionais. Estrutura do sistema operacional Linux e do Windows 2000/XP. Interrupes e chamadas de Sistema.

2. Processos Concorrentes Processos Concorrentes. Condies de Concorrncia. Especificao de Concorrncia. Processos leves (threads). 3. Escalonamento Conceitos Bsicos. Algoritmos de escalonamento. Escalonamento de processos em mquinas paralelas. Escalonamento no Sistema operacional Linux e no Windows 2000/XP. 4. Sincronizao de Processos Princpios da Concorrncia. Algoritmos de Excluso Mtua. Semforos

Instrues Especiais. Regio Crtica Condicional. Regio Crtica. Monitores. 5. Comunicao entre Processos Memria Compartilhada. Troca de Mensagens. Primitivas de Comunicao. Comunicao em Grupo. Chamada Remota de Procedimento. MPI. 6. Deadlock Princpios do Deadlock. Deteco de deadlock. Preveno de Deadlock. Evitar Deadlock.

7. Entrada e sada Dispositivos de entrada e sada. Organizao das operaes de Entrada e Sada. Bufferizao. Drivers dos dispositivos. Entrada e sada nos sistemas Linux e Windows 2000/XP 8. Gerncia de Memria Conceitos bsicos. Parties fixas. Parties variveis. Swapping. Paginao. Segmentao. Estudo de casos: Gerncia de memria no Linux e no Windows 2000/XP.

9. Gerncia de arquivos Conceitos Bsicos. Organizao de arquivos. Diretrios. Armazenamento e recuperao de arquivos. Compartilhamento de arquivos. Gerncia de arquivos no Linux e no Windows 2000/XP.

1 Evoluo e Funcionamento dos Sistemas Operacionais


Evoluo dos Sistemas Operacionais. Objetivos e funcionamento. Estrutura dos Sistemas Operacionais. Chamadas de Sistema. Este captulo apresenta a evoluo dos sistemas operacionais, a partir de suas origens. Sero apresentados tambm os objetivos e a descrio do funcionamento dos Sistemas Operacionais, a estruturao dos SO e o funcionamento das chamadas de sistema.

1.1 Evoluo dos Sistemas Operacionais


Sistemas operacionais so programas que controlam todos os recursos do computador e fornecem a base para o desenvolvimento dos programas de aplicao. um gerenciador de recursos, responsvel pela gerncia do processador, pela gerncia de memria, pela gerncia de arquivos, pela gerncia dos dispositivos de entrada e sada e pelos mecanismos de acesso aos dados. Os sistemas operacionais virtualizam todos os recursos de hardware que gerenciam, criando uma mquina virtual. Por exemplo, os usurios tratam com arquivos, que so entidades lgicas gerenciadas pelo sistema operacional. Uma operao de escrita em um arquivo ser traduzida pelo sistema operacional em uma operao de gravao de dados no perifrico, completamente transparente ao usurio.

Monoprogramao e Multiprogramao Nos sistemas operacionais monoprogramados existe um nico programa de usurio em execuo. Nos multiprogramados existem vrios programas de usurio em execuo simultnea. A figura a seguir mostra a organizao de um sistema operacional monoprogramado. formado por cinco componentes lgicos: Tratador de Interrupes: software do SO responsvel pelo tratamento das interrupes; Drivers dos dispositivos: responsveis pela execuo das operaes de entrada e sada. Existe um driver para cada classe de perifrico; Gerenciador de Arquivos: responsvel pela implementao do sistema de arquivos, permitindo ao usurio o armazenamento e a recuperao de informaes. Seqenciador de programas: mdulo que, ao trmino da execuo de um programa, faz com que o sistema passe a executar um novo programa; Programas de usurios: representa o programa em execuo. Existe um nico programa de usurio na memria. Ao trmino da execuo, um outro programa ser carregado pelo seqenciador de programas e passar a ser executado.

Programas de Usurios Seqnciador de Programas Gerenciador de Arquivos Driver dos Dispositivos Tratador de Interrupes Sistema Operacional Monoprogramado 5

Um sistema operacional multiprogramado suporta a execuo de mltiplos programas de usurios, em paralelo. Em sua organizao possui Tratador de Interrupes, Drivers dos dispositivos, um gerenciador de memria, um gerenciador de processos que possui um escalonador, responsvel pela seleo e disparo de programas, por um gerenciador de arquivos, por um seqenciador de programas e pelos programas de usurios em execuo. Num sistema multiprogramado o tempo do processador distribudo entre os programas em execuo. Cada programa executa por um certo tempo, ou at que solicite uma operao de entrada e sada, ou at que necessite esperar a ocorrncia de algum outro evento. Nestes casos, o sistema operacional executa a rotina de tratamento referente ao pedido do processo e, aps isso, um novo processo selecionado e passa os a ser executado. de A figura a seguir mostra esquematicamente multiprogramado. Programas de usurios Seqenciador de programas Gerenciador de arquivos Gerenciador de processos Gerenciador de memria Drivers dos dispositivos Tratadores de interrupo Sistema Operacional Multiprogramado componentes um sistema operacional

Evoluo dos Sistemas Operacionais

Os primeiros sistemas eram totalmente manuais, com usurios altamente especializados e com um esquema de marcao de horas para utilizao. Os usurios eram tambm os pesquisadores que trabalhavam no desenvolvimento dos equipamentos, e que possuam um grande conhecimento do hardware, o que lhes permitia usar o computador. Estas mquinas no possuam sistema operacional e era necessrio programar diretamente o hardware. Os programas eram escritos em assembler e tinham completo controle sobre a mquina. Cada usurio fazia a reserva de um determinado tempo de utilizao do computador. Os problemas existentes eram significativos: a) O usurio no conseguia terminar o seu trabalho no tempo reservado, o que poderia implicar em recomear a tarefa em uma nova data/hora; b) O usurio gastava muito do tempo reservado depurando o programa, com a mquina ociosa; c) O usurio terminava antes do tempo reservado o seu trabalho e a mquina permanecia ociosa at a chegada de um novo usurio; d) Somente um usurio por vez podia utilizar a mquina. Uma soluo empregada foi adoo de um operador humano, com a funo de receber os diferentes programas dos usurios, execut-los e entregar os resultados. Naturalmente que nem sempre os programas eram executados na ordem em que eram recebidos, podendo esta ordem ser determinada por fatores polticos. O emprego de um operador humano eliminava os problemas a, b, e c, citados anteriormente. No entanto, a mquina continuava sendo monousurio e era executado um programa de cada vez. Alm disso, o seqenciamento de execuo era feito manualmente, pelo operador humano.

Outros problemas importantes existentes eram a necessidade de cada usurio desenvolver seus prprios drivers de acesso aos perifricos e as suas prprias rotinas, por exemplo, matemticas. Uma outra evoluo, mais significativa, foi o desenvolvimento do conceito de monitor residente. Um monitor residente um pequeno ncleo concebido para fazer seqenciamento automtico da execuo de programas. O monitor formado, basicamente, pelos drivers de entrada e sada, por rotinas de biblioteca (reutilizao de cdigo), que possuem cdigo de procedimentos e por um seqenciador automtico. O funcionamento do monitor o seguinte: Loop: carregar o cdigo para execuo; executar; go to Loop; Com monitor residente, os passos para a execuo de um programa so os seguintes 1. Elaborar a lgica da soluo; 2. Programar em uma linguagem de programao (Ex. Fortran); 3. Perfurar os cartes correspondentes a cada comando da linguagem; 4. Entregar os cartes perfurados ao operador humano; 5. O operador humano transfere o programa dos cartes, com uma leitora de cartes perfurados, para um perifrico mais rpido (por exemplo, um tambor magntico); 6. O computador acionado e transfere o programa do tambor magntico para a memria;

7. O programa executado; 8. Os resultados so gravados em fita magntica, impressos, ... Com monitor residente a memria do computador dividida em duas partes, uma para conter o monitor e outra para conter os programas dos usurios. Neste esquema, cada programa executado completamente, sendo que somente aps seu trmino um novo programa carregado para execuo. Trata-se, portanto, de um modelo de monoprogramao. Os problemas existentes com monitor residente eram como saber a natureza do programa a executar, por exemplo, Cobol, Fortran ou Assembler, como distinguir um programa de outro e como distinguir cdigo do programa dos dados. Uma soluo para estes problemas foi introduo do uso de cartes de controle, que fornecem ao monitor residente as informaes necessrias execuo dos programas. $JOB: indica o incio de um programa; $FTN: indica que a linguagem Fortran; $LOAD: indica que o programa deve ser carregado para a memria para execuo; comandos da linguagem de programao

$RUN: indica que o programa dever ser executado; $DATA: indica incio de dados; $EOJ: indica fim de programa. Com cartes de controle, o monitor residente possui as seguintes funcionalidades: Interpretar os cartes de controle, carregar os programas na memria, disparar a execuo dos programas.

O monitor residente um sistema operacional Batch monoprogramado, no qual o computador permanece ainda subutilizado, pois os programas so executados seqencialmente.

Sistemas Operacionais Batch multiprogramados Sistemas operacionais Batch multiprogramados representam uma evoluo ao conceito de monitor residente apresentado anteriormente. Nestes sistemas, os programas de mesmas caractersticas so agrupados e executados em uma seqncia, sem a interveno do operador, e vrios programas so mantidos na memria ao mesmo tempo, sendo o tempo de CPU distribudo entre os programas residentes na memria. Um exemplo de seqncia de programas a ser executado em um sistema operacional batch multiprogramado o seguinte:

$JOB userName 1 $FTN carto 1 carto 2 --carto n $LOAD $RUN carto de dados 1 carto de dados 2 --carto de dados n $EOJ

; identificar o usurio ; carregar o compilador Fortran ; cartes contendo o cdigo do programa

; carregar o programa compilado ; executar o programa ; cartes de dados

; final do programa 10

$JOB userName 2 $FTN carto 1 carto 2 --carto n $LOAD $RUN carto de dados 1 carto de dados 2 --carto de dados n $EOJ

; identifica o usurio ; carregar o compilador Fortran ; cartes contendo o cdigo do programa

; carregar o programa compilado ; executar o programa ; cartes de dados

; final do programa

Duas funes fundamentais para os sistemas multiprogramados so gerncia de memria e escalonamento. Deve existir uma poltica de alocao e liberao de memria para os programas em execuo e devem existir polticas de seleo de programas para a entrega do processador.

Sistemas operacionais de tempo compartilhado (Time sharing) Os sistemas operacionais de tempo compartilhado surgiram no incio dos anos 1960 e se tornaram populares nos anos 1970. Nestes, existe uma comunicao on line entre o usurio e o sistema de computao. O usurio submete requisies ao sistema e recebe as respostas imediatamente. A interao entre o usurio e o equipamento feita com o uso de terminais. O sistema possui um Interpretador de Comandos, que l a linha de comando contendo o nome do programa a ser executado e o carrega para execuo. Aps a execuo de um comando, o Interpretador de Comandos volta a ler o terminal. Assim, o usurio imediatamente compila e executa o seu programa. Um outro aspecto importante 11

que muitos usurios compartilham o uso do computador. um sistema operacional multiusurio.

Nos sistemas operacionais de tempo compartilhado, o interpretador de comandos executa um loop eterno, no qual: loop: l a linha de comando contendo o nome do programa a executar; Carrega o programa para execuo Go to loop;

Nestes sistemas, o tempo de desenvolvimento de um programa muito menor, comparando-se com os sistemas operacionais batch, pois o usurio interage com o equipamento. O usurio edita, compila e executa o seu programa em comunicao direta com o computador. Alm disso, vrios usurios, Os o simultaneamente, um em cada terminal, podem fazer uso da mquina. mesmos de um sistema operacional multiprogramado. Porm,

componentes de um sistema operacional de tempo compartilhado so os seqnciamento de execuo feito por um interpretador de comandos, que possui a funo de interagir com o usurio.

Sistemas Operacionais de Tempo real Sistemas operacionais de tempo real so usados para controlar um dispositivo em uma aplicao dedicada, tais como controle de experimentaes cientficas, imagens mdicas, controle de um processo industrial, na robtica, na aviao, etc. Em muitos destes sistemas, sensores coletam dados que so enviados ao computador, os dados so analisados e executada uma ao, correspondente ao tratamento do sinal recebido e so enviados sinais de resposta. 12

Os sistemas operacionais de tempo real podem ser classificados como Hard real-time system ou Soft real-time system. Um Hard real-time system caracterizado pela necessidade responder a um evento, de uma certa forma, em um intervalo de tempo determinado, sob pena de que uma falha grave poder ser provocada se isso no ocorrer. Por exemplo, pode-se pensar que sensores colocados em um automvel so capazes de detectar a faixa branca pintada nas laterais de uma estrada, gerar um sinal que ser interpretado pelo sistema operacional que dever sinalizar a ocorrncia deste evento e ser gerado, por exemplo, um sinal sonoro, de alerta ao motorista. Se o sinal sonoro no for acionado em um perodo determinado de tempo, um acidente poder ocorrer. Existe, portanto, um intervalo de tempo determinado em que o sistema dever responder a ocorrncia do evento. Soft real-time system so sistemas dedicados a aplicaes que no possuem restries de tempo. Tais sistemas so utilizados na robtica, em algumas aplicaes industriais, etc. Os componentes de um sistema operacional de tempo real so o tratador de interrupes, associados aos eventos, os drivers dos perifricos, associados aos perifricos existentes, um gerenciador de memria e um gerenciador de processos que podem ser mnimos, adequados aplicao. No possui seqenciador de execuo nem interpretador de comandos, visto que os processos que executa so disparados quando ocorrem os eventos aos quais esto associados. Sistemas Operacionais de Rede Um sistema operacional de rede pode ser visto como sendo formada por um conjunto de mquinas interligadas por uma rede de comunicao, cada uma rodando o seu prprio sistema operacional e compartilhando recursos, por exemplo, um servidor de impresso. O acesso remoto a uma outra mquina se faz explicitamente, com comandos de login remoto. Alm disso, o usurio

13

necessita conhecer a localizao dos arquivos e executar operaes especficas para mov-los de uma mquina para outra. Um sistema operacional de rede pode ser construdo a partir de um sistema operacional tradicional, com a incorporao de um conjunto de funes que permitem a comunicao entre os diferentes processadores e o acesso aos arquivos. Um exemplo significativo de sistema operacional de rede Sun Solaris, que possui um sistema de arquivos distribudos, o NFS (Network File System), que permite o acesso aos arquivos independentemente de sua localizao fsica. O NFS um sistema que permite o compartilhamento de arquivos entre as estaes pertencente ao pool de estaes. Mais precisamente, gerencia os file servers e a comunicao entre os file servers. A idia bsica a seguinte: Coleo de clientes e servidores compartilham um sistema de arquivos o Servidores exportam os diretrios; o Clientes, pela operao de montagem, ganham acesso aos arquivos. Uma operao sobre arquivos ou diretrios encaminhada a um componente do sistema denominado de Virtual File System (VFS). Tratandose de um arquivo ou diretrio local, a operao executada e o resultado enviado ao cliente. Se o arquivo ou diretrio remoto, gerada uma mensagem sendo a mesma enviada ao sistema distante, sob a forma de um RPC (Chamada Remota de Procedimento). A operao ser ento realizada no sistema remoto e o resultado ser enviado ao nodo solicitante, onde ser tratada pelo VFS que a encaminhar ao cliente. A figura a seguir ilustra a organizao do NFS.

14

Operaes sobre arquivos

RPC Call Virtual File System RPC reply

Local

Distante

Viso Geral funcionamento do NFS

O NFS suporta sistemas heterogneos e possui um bem definido protocolo cliente/servidor. A operao mount retorna um V-Node, que um identificador de arquivo vlido na rede. As operaes read e write so executadas independente da localizao fsica do arquivo e transparente ao usurio. Uma mquina cliente NFS se ela monta ou importa diretrios. Uma mquina servidora se ela exporta (figura abaixo). arquivos ou arquivos ou diretrios

15

Importa Cliente

Exporta Servidor

Viso Geral do NFS

Um sistema pode ser cliente e servidor, unicamente cliente, unicamente servidor, uma mquina servidora pode ter vrias mquinas clientes e uma mquina pode ser cliente de vrios servidores. O funcionamento do NFS centrado no VFS, que possui as seguintes caractersticas: o Implementado no ncleo do sistema; o Permite acesso a diferentes tipos de sistema de arquivos (Unix, DOS,..); o A cada sistema de arquivos montado corresponde uma estrutura VFS no ncleo; o O sistema de arquivos virtual mapeado no sistema de arquivos real se o arquivo local . A figura a seguir apresenta uma viso geral da arquitetura do NFS.

16

Cliente Chamada de sistema Servidor

Interface VFS

Interface VFS

Local FS

NFS Cliente

Local FS

NFS Servidor

Disco

RPC

Disco

RPC

Arquitetura do NFS

Sistemas Operacionais Distribudos O objetivo de um sistema operacional distribudo o de distribuir a computao entre vrios processadores fsicos e promover o compartilhamento de recursos. Cada processador, no conjunto de processadores, possui sua prpria memria e a comunicao entre os processadores feita atravs de linhas de comunicao. 17

Um sistema operacional distribudo oferece aos usurios a impresso que existe uma nica mquina e um nico sistema operacional, controlando todos os recursos da rede. Em um sistema operacional distribudo, em cada processador executa um ncleo de sistema operacional e a comunicao entre os processadores feita por troca de mensagens (ambientes sem compartilhamento de memria) ou por operaes read remoto e write remoto (com memria virtual compartilhada). operacional distribudo so: Transparncia Para o usurio como existisse uma nica mquina, com um nico sistema operacional. Transparncia de acesso O usurio no deve necessitar saber se o recurso local ou remoto. Transparncia de localizao O nome do recurso no deve ser relacionado localizao; O usurio deve poder acessar o recurso independentemente da mquina na qual est conectado. Alguns requisitos de um sistema

Sistemas Operacionais para Mquinas Paralelas Mquinas paralelas so compostas por mais de um processador operando de forma independente, podendo ter memria comum ou memria distribuda. Nas mquinas paralelas com memria comum existe uma memria que pode ser acessada por qualquer processador da rede de processadores (figura a seguir).

18

Memria

p0

p1

pn

Mquina Paralela com Memria Comum

Nas mquinas paralelas com memria distribuda cada processador possui sua prpria memria e um processador no possui acesso memria dos outros processadores (figura a seguir).

M0

M1

M2

p0

p1

p2

Mquina Paralela com Memria Distribuda

Os objetivos de um sistema operacional para mquinas multiprocessadoras so similares aos de um Sistema Uniprocessador Multiprogramado:

19

Gerenciar recursos; Prover ao usurio a abstrao de uma mquina de alto nvel.

Sistemas operacionais para mquinas paralelas com memria comum Os sistemas operacionais para mquinas multiprocessadoras com memria comum (MOS) possuem paralelismo fsico, em oposio concorrncia nos sistemas uniprocessador, suportando verdadeira execuo paralela de mltiplos processos. Existem trs configuraes bsicas para sistemas operacionais para mquinas paralelas com memria comum: Mestre/escravo, Mestre flutuante e Simtrico. Mestre/Escravo: Um Processador (o mestre) monitora o status do sistema: Trata todas as chamadas de sistema; Atribui os processos a serem executados aos demais. As vantagens desta configurao so facilidade de projetar e implementar e o fato de permitir a execuo paralela de um nico processo. As desvantagens desta abordagem so: Serializao das chamadas de sistema porque somente o mestre as executa; O mestre normalmente no fica com muita carga; O mestre pode se tornar um gargalo. Mestre flutuante: O SO inteiro tratado como uma seo crtica, e um processador por vez o executa. As vantagens desta abordagem so: Todos os processadores so completamente utilizados;

20

Permite execuo paralela de uma task . A principal desvantagem que o mestre continua sendo o gargalo do sistema. Simtrico: O SO pode ser acessado por mltiplos processadores, cada um acessando diferentes sees crticas. Este tipo de sistema possui uma configurao mais verstil e permite a execuo paralela de um nico processo. Trata-se, no entanto, de uma organizao mais difcil de projetar e implementar, que necessita de um kernel que possa ser executado em paralelo (reentrante). Um aspecto altamente importante que muitas chamadas de sistema so executadas concorrentemente.

Sistemas Operacionais para mquinas paralelas com memria distribuda Um sistema operacional para mquinas paralelas com memria distribuda possui um ncleo que executa em cada processador eoferece servios de gerncia de processos: criao e destruio locais ou distantes, de comunicao entre processos em um mesmo processador ou em processadores diferentes, de sincronizao e tambm de gerncia de memria. A isso se pode ainda acrescentar servios como gerncia de arquivos e de entrada e sada. Um ncleo de sistema operacional paralelo pode ser organizado de maneira clssica. Cada processador possui um ncleo monoltico ao qual se incorporam a gerncia de comunicaes e o acesso aos servios clssicos distantes. O conjunto de ncleos monolticos cooperantes forma um ncleo monoltico paralelo. Uma outra soluo consiste na abordagem dita Microkernel. Um Microkernel essencialmente um ncleo de comunicao entre processos, de gerncia de processos e de gerncia de memria. No oferece nenhum dos servios clssicos que so assegurados por processos servidores. Por exemplo,

21

a abertura de um arquivo se traduz em uma mensagem do cliente ao servidor gerente de arquivos solicitando o servio. O servidor executa a solicitao e envia os resultados. As vantagens de um Microkernel so a extensibilidade e a modularidade. Os recursos do sistema so acessados da mesma maneira de acordo com um protocolo cliente/servidor. Para acrescentar um novo servio basta acrescentar um novo servidor. Um Microkernel Paralelo portanto composto por um conjunto de Microkernels locais cooperantes, um em cada nodo da mquina paralela. A funo de comunicao de cada Microkernel estendida de maneira a permitir o acesso aos servios oferecidos por servidores distantes. O ponto crucial de um Microkernel Paralelo o Microkernel de comunicao que permite a comunicao entre processos sobre um mesmo processador ou em processadores diferentes, de acordo com um protocolo cliente/servidor. O Microkernel de comunicao possui como funes bsicas receber mensagens originrias de outros processadores, receber resultados de operaes executadas remotamente e de enviar mensagens destinadas a outros processadores.

1.2 Estrutura e Funcionamento dos Sistemas Operacionais


Funcionamento dos Sistemas Operacionais Os sistemas operacionais reagem a eventos, que representam solicitao de servios. Por exemplo, uma operao de leitura no programa de usurio ser realizada por uma chamada de sistema que corresponder a uma funo executada pelo sistema operacional que solicitar ao controlador do perifrico a transferncia dos dados para o endereo de memria informado no pedido do servio. Quando a transferncia se completar, o controlador do perifrico pode gerar uma interrupo, que ser sentida pelo processador e que far com que o sistema operacional execute uma rotina de tratamento da interrupo. Neste

22

exemplo, os dados solicitados pelo programa do usurio se encontram na memria principal, na rea de dados do programa que solicitou ou na rea de buffers gerenciada pelo sistema operacional. Se for na rea de buffers, o sistema operacional os copiar para a rea de dados do programa. Estando os dados na rea do programa, o mesmo poder novamente executar. A figura abaixo esquematiza o funcionamento de um sistema operacional.

Viso esquemtica do funcionamento de um Sistema Operacional Estrutura dos Sistemas Operacionais Um sistema operacional um programa, formado por diversos processos concorrentes, situados entre os programas de aplicao e o hardware, que virtualiza o hardware tornando-o mais simples de ser utilizado. Desta forma, o desempenho do sistema operacional tem uma influncia fundamental na performance das aplicaes. A forma de estruturao dos sistemas operacionais tm evoludo, na tentativa de encontrar a estrutura mais apropriada. A seguir sero apresentadas as principais formas de estruturao dos sistemas operacionais. 23

Monolticos O SO organizado como uma coleo de processos seqenciais cooperantes, que recebem as solicitaes dos usurios (chamadas de sistema), as executam e devolvem um resultado.

Sistema Operacional Monoltico

Hierrquico Um sistema operacional pode ser organizado sob a forma de um conjunto de processos seqnciais cooperantes, cada um executando uma funo bem definida. Assim, cada programa de usurio, cada driver de perifrico, a gerncia de memria, o escalonamento, etc. executado por um processo. O funcionamento do sistema o resultado da cooperao entre os processos seqenciais e a ao coordenada destes. Como as velocidades de execuo dos diferentes processos que formam o sistema operacional indeterminada, existe a necessidade de mecanismos explcitos de sincronizao, para estabelecer o perfeito funcionamento do sistema. No sistema operacional THE, construdo por Dijkstra em 1968, todas as atividades do sistema so divididas em um certo nmero de processos seqnciais. Estes processos implementam as abstraes dos diferentes componentes do sistema e so colocados nos vrios nveis lgicos nos quais o sistema foi organizado. 24

O sistema possui seis nveis lgicos: Nvel 0: responsvel pela alocao do processador para os processos em execuo e pelo tratamento das interrupes. Nvel 1: responsvel pela gerncia de memria. No sistema foi utilizado o conceito de pginas e foi feita uma distino entre pginas de memria e pginas de tambor magntico. Uma pgina de tambor magntico possui exatamente o tamanho de uma pgina de memria e um mecanismo de identificao de segmento permite a existncia de um nmero maior de pginas na memria secundria. principal ou no. Nvel 2: interpretador de mensagens: trata da alocao da console do sistema ao operador, para permitir a comunicao deste com os processos em execuo. Quando o operador aperta uma tecla, um caractere enviado ao interpretador de comandos, que pode ento estabelecer uma conversao com um processo. Nvel 3: neste nvel encontram-se os processos responsveis pelos input streams e pelos output streams. Este nvel implementa uma console virtual para cada processo, os quais compartilham uma mesma console fsica. O sistema permite uma nica conversao por vez, usando para tal mecanismos de excluso mtua. Este nvel utiliza as funcionalidades do nvel 2 (interpretador de comandos) para se comunicar como operador. Isto necessrio, por exemplo, no caso de problemas com um perifrico. Nvel 4: formado pelos programas de usurio. Nvel 5: representa o operador do sistema. A figura a seguir ilustra a estrutura do sistema. Uma varivel indica se a pgina est na memria

25

Organizao do sistema operacional THE

A organizao hierrquica, pelo fato de ser formada por processos independentes, interessante de ser utilizada, pois adequada a verificao da correo do funcionamento e permite o desenvolvimento modular, visto que cada processo seqencial pode ser implementado de maneira completamente independente dos demais. 26

sotnemges ed rodalortnoC

rodassecorp od oacolA

snegasnem ed rodaterpretnI

erawdraH

oirusu ed samargorP

S/E ed sossecorP

rodarepO

Mquinas virtuais Uma mquina virtual formada por recursos virtuais que so mapeados para recursos reais. Desta forma, uma mquina com grande capacidade de memria pode ser particionada em vrias mquinas virtuais, com menos recursos que a mquina real. O acesso a uma pgina de memria na mquina virtual mapeado (traduzido) em um acesso a uma pgina de memria real. As instrues da mquina virtual so traduzidas para instrues da mquina real e executadas. O VM (Virtual Machine) da IBM um exemplo de sistema operacional que utiliza o conceito de mquinas virtuais. Cada sistema operacional VM controlado por um programa chamado de Control Program, que gerencia o hardware fsico, cria uma mquina virtual para cada usurio do sistema, sendo esta mquina virtual uma simulao exata de um sistema operacional (IBM/370 ou IBM/390). Cada usurio executa seus programas armazena seus dados, etc. sem interferncia e sem interferir com os outros usurios. O Control Program o componente fundamental do sistema e roda diretamente no hardware do computador. Suas funes so gerenciar o hardware do computador, gerenciar mquinas virtuais (criao, deleo, ...), fazer o escalonamento, etc.

Microkernel A organizao Microkernel baseada no modelo cliente/servidor, na qual os servios do sistema so implementados por servidores especializados. Um Microkernel (mnimo) responsvel pelo tratamento das interrupes, pela gerncia de memria nos seus aspectos mais bsicos, e pelas funes de mais baixo nvel do escalonamento. Todos os servios do sistema so implementados por servidores especializados, em um nvel lgico acima do Microkernel. Os

27

Clientes (programas de aplicao) solicitam os servios ao SO (Microkernel) que os encaminha aos servidores. Os servidores executam um loop eterno, no qual recebem a solicitao de um servio, o executam, enviam o resultado ao Microkernel e voltam a esperar a solicitao de um novo servio. O Microkernel recebe do servidor o resultado e o transmite ao cliente, que de posse do resultado do servio pedido, volta a executar o cdigo da aplicao. A figura a seguir exemplifica uma organizao Microkernel. As vantagens da organizao Microkernel so a modularidade e a facilidade de se acrescentar novos servios, que consiste na incorporao de um novo servidor.

Organizao Microkernel

Exokernel A estruturao de um sistema operacional em exokernel elimina a noo de que o mesmo deve fornecer uma abstrao total do hardware sobre a qual so construdas todas as aplicaes. A idia que, devido s necessidades distintas de diferentes aplicaes, o sistema operacional deve, adequadamente, fornecer os recursos necessrios a cada aplicao. Desta forma, o exokernel possui um conjunto bsico de primitivas de baixo nvel, com as quais gerencia completamente o hardware e, cada aplicao, utiliza somente o subconjunto adequado s suas necessidades. Assim, por exemplo, servidores podem implementar abstraes tradicionais, adequadas s aplicaes s quais se destinam.

28

Estudo de caso: Organizao do sistema operacional Linux O sistema operacional Linux formado por quatro grandes nveis: Programas de Aplicao, Servios do Sistema, Kernel e Controladores dos Dispositivos. Os programas de Aplicao representam as aplicaes dos usurios. Os servios do sistema so, tipicamente, o Shell, as bibliotecas, os compiladores, e a interface grfica. O kernel monoltico, e fornece ao usurio uma abstrao do hardware, permitindo ao usurio o uso da mquina. Os controladores dos dispositivos implementam a interface entre o sistema e o hardware. A figura abaixo apresenta os quatro principais nveis do Linux.

Programas de usurios Servios do sistema Kernel do Linux Controladores dos dispositivos Sistema Operacional Linux

O kernel do Linux formado por cinco subsistemas: 1. Escalonador (sched), responsvel por selecionar processos para execuo e entregar o processador ao processo selecionado. 2. O gerente de memria (MM), que permite a existncia de vrios processos na memria principal. O MM implementa memria virtual, que permite a execuo de processos maiores que a memria real. 3. O Virtual File System (VFS) que gerencia o sistema de arquivos. Um conceito implementado o de independncia do dispositivo, que cria uma interface uniforme, comum a todos os diferentes tipos de dispositivos. 29

Implementa tambm diferentes formatos de arquivos, compatveis com outros sistemas operacionais. 4. Interface de rede (Net), que permite o acesso as redes de comunicao. 5. Inter-Process Communication (IPC), subsistema que implementa os diversos mecanismos de comunicao entre processos.

1.3 Interrupes e Chamadas de Sistema


Um sistema de computao formado por uma Unidade Central de Processamento (UCP) que acessa a memria para fazer busca de instrues e dados, executa as instrues e interage com os perifricos nas operaes de entrada e sada. Em relao a UCP, os perifricos so extremamente lentos, e operam de forma assncrona. A comunicao da UCP com o perifrico feita atravs de registradores. Devem existir trs registradores: Registrador de dados: Neste registrador o processador coloca os dados a serem gravados no perifrico e o perifrico coloca os dados resultantes de uma operao de leitura. Registrador de status: Contm informaes sobre o estado do perifrico (livre/ocupado). Registrador de controle: Neste registrador o processador escreve os comandos a serem executados pelo perifrico. Os dispositivos de entrada e sada podem ser mapeados em um espao de endereamento separado, distinto do espao de endereamento de memria e a comunicao e a troca de informaes entre o processador e o controlador do perifrico feita atravs deste espao, ou o espao de endereamento pode ser mapeado diretamente na memria, ocupando endereos no espao de memria.

30

Com o espao de endereamento distinto do espao de endereamento de memria so necessrias instrues especficas de leitura e escrita de dados (Ex. IN e OUT). IN usada para leitura de dados dos registradores usados na comunicao com o controlador do perifrico. OUT usada para escrita de dados nestes registradores. Com o I/O mapeado na memria, para a comunicao entre o processador e o controlador do perifrico, podem ser usadas todas as instrues que fazem movimentao de dados na memria. Tipos de Entrada e Sada I/O Programado As operaes de entrada e sada so realizadas sob o controle do Sistema Operacional, que fica testando, na interface com o perifrico, o estado do I/O (pooling). O controlador do perifrico no interrompe a CPU. Ex. de funcionamento: 1. SO envia ao perifrico um comando 2. Ler status do perifrico 3. Se Status NOT ready goto 2 4. Se comando executado de leitura ento Ler informao do perifrico Escrever a informao lida na memria 6. Se existe novo pedido de I/O ento goto 1 O grande inconveniente do I/O programado que a maior parte do tempo do processador desperdiado testando o status do perifrico (pooling: linhas 2 e 3). I/O com interrupo

31

O perifrico, ao trmino de uma operao de transferncia de dados (entrada ou sada), sinaliza o processador gerando um pedido de interrupo. O processador passa ento a executar o procedimento que implementa a funo correspondente a interrupo ocorrida. Existe um tratamento especfico cada fonte de interrupo. Como a ao do perifrico independente da ao do processador, durante a operao de transferncia de dados o processador fica livre para executar outros processos. Acesso Direto Memria (DMA) A informao transferida diretamente do perifrico para a memria sem interveno do processador. Ao trmino da operao de transferncia de dados gerada uma interrupo, que ser tratada pelo Sistema Operacional. Com DMA o processador, durante as operaes de I/O, o processador fica executando outros processos.

Origem das Interrupes As interrupes podem ser: a) Geradas pelo programa: implementadas com o uso de instrues especiais (ex. INT, TRAP). b) Geradas por um erro: diviso por zero, referncia a memria fora do espao permitido, etc. c) Geradas pelo relgio; d) Geradas pelos perifricos: sinalizao de final de operao de E/S ou condio de erro. Tratamento de Interrupes O sistema operacional reage ocorrncia de interrupes, que provocam a execuo da rotina de tratamento correspondente fonte de interrupo. Tratamento de interrupes de software

32

Estas interrupes so geradas por uma instruo especial (int, trap, ...). Quando ocorre uma interrupo de software: O programa para de executar; O sistema operacional executa o servio solicitado pelo processo do usurio ou o encaminha ao perifrico (no caso de E/S); Ao final da execuo do servio, o controle retorna ao processo solicitante ou um novo processo selecionado (no caso do processo solicitante necessitar esperar pela realizao do servio).

Tratamento de interrupes de hardware Quando ocorre uma interrupo de hardware, as aes executadas pelo processador so as seguintes: O processador acaba execuo da instruo atual; O processador testa existncia de interrupo; O processador salva estado atual; O processador carrega contador de programa com o endereo da rotina de tratamento da interrupo; A execuo comea na rotina de tratamento da interrupo; A rotina de tratamento da interrupo executa; O contexto de execuo anterior restaurado; A execuo retorna para a rotina interrompida.

Chamadas de Sistema Os servios oferecidos pelo sistema operacional so acessveis aos programas de aplicao sob a forma de chamadas de sistema. Portanto, as chamadas de sistema so a interface entre os programas sendo executados e o sistema operacional e geralmente so implementadas com o uso de instrues de baixo 33

nvel. Um processo em execuo, por exemplo, para abrir um arquivo utiliza uma chamada de sistema (open). Durante o tempo em que o sistema operacional trata a chamada de sistema, o processo que a solicita permanece bloqueado (a espera do recurso, no caso o arquivo) e um novo processo selecionado para execuo. Ao trmino da operao de abertura do arquivo, o sistema operacional torna o processo requisitante novamente apto a rodar. A figura a seguir mostra o grafo de transio de estados dos processos em uma chamada de sistema.

Os processos em execuo sofrem transio entre trs estados: rodando, bloqueado e pronto para rodar. O processo quando submetido para execuo inserido em uma fila de processos aptos para executar, est pronto para rodar. Quando o mesmo selecionado passa para o estado rodando. Quando faz uma chamada de sistema perde o processador (por exemplo, solicitou uma operao de entrada e sada) e passa para o estado bloqueado. Ao trmino da chamada de sistema passa para o estado pronto para rodar e inserido na fila de aptos. As chamadas de sistema podem ser relacionadas ao controle de processos, a manipulao de arquivos, comunicao, etc. a manipulao de dispositivos,

34

Chamadas de sistema relacionadas ao controle de processos Criar; Terminar; Carregar, executar; Esperar por evento, sinalizar evento; Esperar passagem de tempo; Alocar e liberar memria; etc.

Chamadas de sistema para Manipulao de arquivos: Criar, deletar; Abrir, fechar; Ler, escrever; Posicionar; etc.

Chamadas de sistema para Manipulao de dispositivos: Alocar, liberar; Ler, escrever; Manuteno de informao do sistema. e.g.: ler, modificar a hora; Etc.

35

Chamadas de sistema referentes comunicao entre processos: Criar, deletar canais de comunicao; Transferir informao; etc.

Implementao das Chamadas de Sistema A implementao das chamadas de sistema depende do hardware existente. Por exemplo, os processadores Intel possuem uma instruo especial, INT, usada para troca de contexto e que transfere o controle da execuo para o sistema operacional. Em processadores que no possuem este tipo de instruo, outras solues necessitam ser utilizadas, por exemplo, chamada de uma rotina especial para executar o servio. Outro aspecto importante a passagem de parmetros para o sistema operacional. Isto pode ser feito atravs de registradores ou atravs de um bloco de memria, cujo endereo colocado em um registrador. Por questes de performance, desejvel que a passagem de parmetros seja feita com o uso de registradores. Esta soluo somente no pode ser utilizada para aquelas chamadas de sistema que possuem um nmero de parmetros maior do que o nmero de registradores disponveis, o que na prtica so muito poucas. Para estas chamadas de sistema pode ser utilizada a outra soluo, na qual o endereo da rea de parmetros colocado em um registrador. Exemplo de implementao de chamada de sistema A seguir ser apresentado um exemplo de implementao da chamada de sistema read, a partir de um programa escrito em C.

Programa do usurio

36

main() { read ( fd, &b, 20) ; } Biblioteca _read ( int fd, char *b, int l ) { move fd, regA; move b, regB move l, regC move READ, regD int 80H; }

No exemplo acima, o usurio faz uma chamada de sistema read, passando como parmetros o identificador do arquivo (fd), dados a serem lidos (20). Esta chamada de sistema dispara a execuo do procedimento de biblioteca read, que coloca os parmetros recebidos em registradores e, com o uso da instruo especial int, passa o controle para o sistema operacional. A instruo int coloca na pilha a palavra de status do sistema e o program counter e atribudo ao program counter o endereo que se encontra na posio 80H do vetor de interrupes. A rotina chamada salva o restante do contexto e invoca o procedimento correspondente chamada de sistema (read). Aps o acionamento do driver, que feito pela rotina que executa o tratamento da chamada de sistema, um novo processo selecionado para execuo. O processo que efetuou a chamada de sistema read ser acordado (estar pronto para executar) ao trmino da transferncia dos dados do perifrico para o endereo de memria colocado na chamada de sistema, o que ser feito pelo sistema operacional. 37 o endereo da rea de memria na qual os dados lidos devem ser armazenados (&b) e o tamanho dos

Chamadas de sistema no Linux O sistema operacional Linux faz distino entre o espao de endereamento do usurio e o espao de endereamento do sistema. A um processo de usurio no permitido acessar diretamente os servios do kernel. Nas operaes que necessitam ser desenvolvidas pelo kernel, o processo do usurio solicita o servio ao sistema operacional com uma chamada de sistema. feita com o uso da instruo int 80h. O Linux suporta mais de 200 chamadas de sistema, que podem ser acionadas pela instruo int 80h. Cada chamada de sistema possui um nmero que a distingue das demais, que passado para o kernel no registrador EAX. O nmero de mximo de parmetros para uma chamada de sistema sete, passados para o kernel pelos registradores %eax, %ebx, %ecx, %edx, %esi e %edi e %ebp. Para chamadas de sistema com mais de sete parmetros, utilizado o registrador (%ebx) para passar um endereo de memria do processo que contm os parmetros restantes. O arquivo /usr/include/asm/unistd.h contm o nome e o nmero das chamadas de sistema. As linhas a seguir apresentam os nmeros associados a algumas chamadas de sistema existentes no Linux. Nos processadores Intel, a troca de contexto, do modo usurio para modo kernel,

#define #define #define #define #define #define #define #define #define

__NR_exit __NR_fork __NR_read __NR_write __NR_open __NR_close __NR_waitpid __NR_creat __NR_link

1 2 3 4 5 6 7 8 9

38

#define __NR_unlink #define __NR_execve

10 11

Assim, exit a funo 1, fork a 2, read a 3, etc. A seguir sero apresentadas algumas chamadas de sistema do sistema operacional Linux, referentes ao controle de processos e a manipulao de arquivos. Chamadas de sistema para controle de processos: fork: cria um novo processo que uma cpia do processo pai. O processo criador e o processo filho continuam em paralelo, e executam a instruo seguinte chamada de sistema. Wait: suspende a execuo do processo corrente at que um filho termine. Se um filho terminou antes desta chamada de sistema(estado zumbie), os recursos do filho so liberados e o processo no fica bloqueado, retornando imediatamente. Exit: termina o processo corrente. Os filhos, se existirem, so herdados pelo processo Init e o processo pai sinalizado. Exec: executa um programa, substituindo a imagem do processo corrente pela imagem de um novo processo, identificado pelo nome de um arquivo executvel, passado como argumento. Kill: usada para enviar um sinal para um processo ou grupo de processos. O sinal pode indicar a morte do processo. Sleep: suspende o processo pelo tempo especificado como argumento.

Chamadas de sistema para manipulao de arquivos: Um conjunto de primitivas permite aos usurios executar operaes em arquivos e diretrios. Algumas primitivas para manipulao de arquivos so:

39

Open: abre o arquivo especificado, convertendo o nome do arquivo no descritor do arquivo, um valor inteiro no negativo.

Close: fecha um descritor de arquivo, liberando bloqueios e permitindo que o arquivo possa ser acessado por outros usurios.

Read: recebe trs argumentos (descritor do arquivo (fd), buffer (b) e quantidade de bytes que devero ser lidos (l). Tenta ler do arquivo fd l bytes, e os armazena no buffer b.

Write: recebe trs argumentos (descritor do arquivo (fd), buffer (b) e quantidade de bytes que devero ser escritos (l). Tenta escrever no arquivo fd l bytes, transferidos a partir do endereo b.

Creat: cria um novo arquivo. Pipe: retorna em um vetor de dois elementos um par de descritores de arquivos criados para permitir a comunicao entre processos. O escritor retornado na entrada 0 do vetor usado para leitura no pipe e o retornado na entrada 1 usado para escrita no pipe.

Link: cria um sinnimo para um arquivo j existente. Os dois nomes se referem ao mesmo arquivo.

Unlink: elimina um nome de arquivo. Tratando-se do ltimo nome associado ao arquivo, o mesmo deletado.

Lseek: coloca o byte corrente do arquivo na posio indicada pelo argumento recebido.

Para executar operaes em diretrios as principais primitivas so: mkdir: cria um novo diretrio com o nome especificado pelo argumento. rmdir: remove o diretrio especificado. ls: lista o contedo do diretrio especificado.

40

chmod: usada para modificar os direitos de acesso aos arquivos especificados.

O programa a seguir exemplifica o uso de chamadas de sistema em um programa escrito em assembler.


# Exemplo de programa que executa chamadas de Sistema no Linux

# Para mont-lo digite as syscall.s -o syscall.o # Para gerar o executvel digite ld -s syscall.o

-o syscall

.data O_RDONLY STDOUT SYS_EXIT SYS_READ SYS_WRITE SYS_OPEN SYS_FORK len file: msg: .comm .text .global _start: # Al mov mov mov mov int _start = = = = = = = = 0 1 1 3 4 5 2 12

# Seo de dados inicializados

.string .string buf, 512

"Teste.txt\0" # Arquivo a ser lido "Alo mundo!\0" # Mensagem a ser escrita em STDOUT # buffer com 512 Bytes # Seo de cdigo

mundo $len, %edx $msg, %ecx $STDOUT, %ebx $SYS_WRITE, %eax $0x80

# # # # #

Tamanho da mensagem apontador para o buffer Arquivo de sada: STDOUT Nmero da chamada de sistema (write) Chamada do kernel

# int open (const char *pathname, int flags, mode_t mode) mov $O_RDONLY, %edx # Abertura do arquivo para leitura mov $0 , %ecx # Flag para abertura (0) mov $file, %ebx # Nome do arquivo a ser aberto mov $SYS_OPEN, %eax # Nmero da chamada de sistema (open) int $0x80 # Chamada do kernel # int read(int fd, void *buf, size_t count) mov $40, %edx # Quantidade de bytes a serem lidos mov $buf, %ecx # apontador para o buffer mov %eax, %ebx # Descritor do arquivo a ser lido

41

mov $SYS_READ, %eax int $0x80

# Nmero da chamada de sistema (read) # Chamada do kernel

# int write(int fd, const void *buf, size_t count) mov $40, %edx # Tamanho da mensagem mov $buf, %ecx # apontador para o buffer mov $STDOUT, %ebx # Arquivo de sada: STDOUT mov $SYS_WRITE, %eax # Nmero da chamada de sistema (write) int $0x80 # Chamada do kernel # int _fork() mov $SYS_FORK, %eax int $0x80 # Al mov mov mov mov int mundo $len, %edx $msg, %ecx $STDOUT, %ebx $SYS_WRITE, %eax $0x80

# No. da chamada de sistema (sys_fork) # Chamada do kernel

# # # # #

Tamanho da mensagem apontador para o buffer Arquivo de sada: STDOUT Nmero da chamada de sistema (write) Chamada do kernel

# void _exit(int status) mov $0, %ebx # Cdigo do exit mov $SYS_EXIT, %eax # Nmero da chamada de sistema (exit) int $0x80 # Chamada do kernel

O programa apresentado acima formado por sete chamadas de sistema: write, que escreve o string Al mundo na sada padro (console), open que abre o arquivo teste.txt para leitura, read que l um string de at 40 caracteres do arquivo teste.txt e o armazena em buf , write que escreve na sada padro (console) o contedo lido pela primitiva read, fork que cria um novo processo, write, executada pelos dois processos, que escreve na sada padro o string Al mundo e exit, executada pelos dois processos para finalizar a execuo.

Exerccios
1. Escreva o pseudo-cdigo do procedimento executado pelo sistema operacional no tratamento de uma interrupo de relgio. 2. Compare as organizaes Monoltica e Microkernel.

42

3. Descreva o funcionamento de um sistema operacional baseado no modelo Microkernel. 4. Descreva as funcionalidades necessrias em um sistema operacional monoprogramado de uso geral. Que funcionalidades devem ser acrescentadas em um sistema deste tipo para transform-lo em um sistema operacional multiprogramado de uso geral? Justifique. 5. Escreva a rotina de biblioteca sleep(t), que faz com que o processo que a executa fique bloqueado por t segundos, sabendo que os parmetros devem passados para o SO atravs dos registradores (R0, R1, R2, ...) e que existe uma instruo especial (INT) que serve para troca de contexto. 6. Descreva todos os passos executados pelo sistema operacional na criao de um processo. 7. Apresente os estados que um processo assume durante a sua execuo e faa o grafo de transio, indicando o evento causador da transio. 8. Escreva o pseudo-cdigo do procedimento executado pelo sistema operacional no tratamento de uma interrupo do disco. 9. Escreva os procedimentos save_Context() e restore_context() , executados pelo sistema operacional para, respectivamente, fazer salvamento e restaurao de contexto. Considere que o sistema possui dois registradores de uso geral (R0 e R1), dois registradores utilizados para gerncia de memria (Mbase e Msize), respectivamente base e deslocamento, um registrador Stack Pointer (SP), um acumulador (AC) e um apontador de instrues (PC). Defina a estrutura de dados na qual so mantidas as informaes sobre os processos (descritor de processos) e observe que o contexto do processo salvo em seu registro descritor. Leve em conta a existncia de uma operao mov op1, op2 onde op1 e op2 podem ser variveis ou registradores.

43

10. Justifique a necessidade da existncia da tabela de descritores de processos em sistemas multiprogramados. Esta tabela necessria em sistemas monoprogramados? Porque? 11. Sabendo que a chamada de sistema wait( int flag) bloqueia o processo que a executa at que um processo filho termine (se o argumento passado como parmetro for igual a 1 o processo fica bloqueado at que todos os filhos terminem) e que a chamada de sistema exit() termina o processo que a executa e acorda o processo pai se o mesmo estiver bloqueado (pela primitiva wait): a) Escreva os procedimento de biblioteca que implementam as chamadas de sistema wait( int flag) e exit(), sabendo que as informaes (parmetros) necessrias para a realizao do servio devem ser colocadas em registradores (R1, R2, ...), que a identificao do servio a ser executado pelo SO deve ser colocada no registrador R0 e que existe uma instruo int 80H utilizada para troca de contexto. b) Descreva os procedimentos executados pelo sistema operacional na realizao destes servios.

44

2. Entrada e Sada
Introduo. Dispositivos de entrada e sada. Organizao das operaes de Entrada e Sada. Bufferizao. Drivers dos dispositivos. Estudo de casos: Linux e Windows NT Este captulo ser organizado em cinco sees:

2.1 Introduo
Nesta seo sero apresentados alguns conceitos sobre os subsistemas de entrada e sada, ressaltando sua importncia no projeto de um sistema operacional.

2.2 Dispositivos de entrada e sada


Nesta seo ser apresentado um overview sobre monitores de vdeo e discos magnticos. Sero descritas as organizaes e o funcionamento destes perifricos, de maneira a permitir a compreenso dos sistemas de entrada e sada implementado pelos sistemas operacionais.

2.3 Organizao das operaes de entrada e sada

45

Esta seo ser dedicada ao estudo da organizao dos sistemas de entrada e sada, nos diferentes nveis: interface com o usurio, sistema operacional e drivers dos dispositivos.

2.4

Drivers dos dispositivos

Nesta seo sero estudadas a organizao e o funcionamento dos driver dos dispositivos, rotinas do sistema operacional que implementam as operaes de sada. Particularmente, sero estudados os drivers dos monitores de vdeo e de discos magnticos.

2.5 Estudo de casos: entrada e sada no Linux


Nesta seo ser estudada a organizao do sistema de entrada e sada do sistema operacional Linux.

46

3. Processos Concorrentes
Processos so programas carregados na memria do computador para execuo, e podem ser classificados como leves e pesados. Este captulo dedicado ao estudo dos processos concorrentes. Apresenta o conceito de processos concorrentes, os estados dos processos, as transies de estado, as operaes sobre processos concorrentes e mecanismos de especificao de concorrncia.

3.1 Processos Concorrentes


Os processadores executam instrues que representam algoritmos. Um processo uma entidade abstrata, formada pelos recursos de hardware e pela execuo das instrues referentes a um algoritmo sendo executado pelo processador. Um algoritmo programado em uma linguagem de programao, por exemplo C, e o programa compilado (cdigo objeto) carregado na memria para execuo. Pode-se classificar os processos em dois tipos: Processos pesados e Processos leves. Os processos pesados so os processos tradicionais. Possuem uma thread inicial que comea a sua execuo (ex. main de um programa C), executam um cdigo seqencial e normalmente so carregados do disco para execuo. Processos leves (threads) so criados para permitir paralelismo na execuo de um processo pesado. As principais caractersticas dos processos leves so:

47

Cada um roda um cdigo seqencial; Possuem sua prpria pilha de execuo e o seu prprio program counter; Compartilham o uso do processador; Podem criar processos (threads) filhos; Compartilham o mesmo espao de endereamento (dados globais).

Um processo (Pesado ou Leve) est no estado running se suas instrues esto sendo executadas pelo processador. Est em um estado ready se possui condies para ser executado e est esperando pelo processador, e est em um estado blocked se est a espera de alguma condio para rodar, por exemplo, est a espera de uma operao de entrada e sada. A figura a seguir ilustra a transio de estados dos processos.

Um processo passa do estado ready para o estado running quando selecionado, ganha o processador e suas instrues comeam a ser executadas. Passa de um estado blocked para ready quando ocorre o evento pelo qual estava esperando, e passa de um estado running para blocked quando necessita esperar pela ocorrncia de um evento (ex. Operao de entrada e sada). A transio de running para ready ocorre em sistemas que atribuem 48

fatias de tempo do processador aos processos em execuo. Quando este tempo termina, o processo perde o processador e passa para o estado ready, a espera novamente do processador.

3.2 Condies de Concorrncia


Supondo que trs processos compartilhem uma varivel x, sobre a qual dois executam operaes de modificao e de consulta, a ordem em que estas operaes so feitas importante. Se a varivel x for modificada simultaneamente pelos dois processos, o valor impresso ir depender da ordem em que as operaes de escrita forem realizadas. Por exemplo, se x = 5, na seqncia de operaes x = x + 10 ; (P0) x = x + 15 ; (P1) print x ; (P2) o processo P2 ir imprimir o valor 30. Por outro lado, se o comando print for executado aps a primeira atribuio, o valor impresso ser 15. Assim, o valor da varivel x que ser impresso ir depender da ordem de execuo dos comandos, sendo portanto indeterminado. As condies de Bernstein[Bernstein 66] so usadas para verificar se um programa determinstico. O conjunto read e o conjunto write de uma aplicao A so respectivamente o conjunto das variveis lidas (consultadas) por A e escritas por A. O conjunto read de uma aplicao B, R(B), a unio dos conjuntos read de todas as operaes de B. Similarmente, o conjunto write de B, W(B), a unio dos conjuntos write de todas as operaes de B. Por exemplo, se B for: x = u + v;

49

y = x * w; ento R(B) = {u, v, x, w}, W(B) = {x, y}. Observe que x faz parte do conjunto read de B, R(B) e do conjunto write de B, W(P). As condies de Bernstein so: Considerando dois processos P e Q, se
a)

A interseco do conjunto write de P, W(P) com o conjunto write de Q, W(Q) vazia, e

b)

A interseco do conjunto write de P, W(P) com o conjunto read de Q, R(Q) vazia, e

c)

A interseco do conjunto read de P, R(P) com o conjunto write de Q, W(Q) vazia, ento

a execuo de P e Q determinstica.

Grafos de precedncia Um grafo de precedncia um grafo dirigido, acclico onde os ns representam atividades seqenciais e onde um arco de um n i para um n j indica que a atividade i deve terminar antes que a atividade j possa comear. Um n em um grafo de precedncia pode representar um processo para o sistema operacional, ou pode representar uma nica instruo, a ser executada por uma mquina paralela (granularidades diferentes). Considerando o seguinte programa seqencial: a = x + y; (s0) b = z + 3; (s1) c = a + b; (s2)

50

d = f + g; (s3) e = d + 5 ; (s4) h = e + c ; (s5) O grafo de precedncia deste programa seqencial o seguinte:

s0

s1

s3

s2

s4

s5 Grafo de processos para o programa seqencial acima Neste grafo de precedncia, os comandos s0, s1 e s3 podem ser executados em paralelo. A execuo de s2 somente pode comear depois do trmino de s0 e s1, a execuo de s4 somente depois do trmino de s3. s5 somente pode ser executado aps o final de s2 e s4. Dois aspectos fundamentais ressaltam pela anlise dos grafos de precedncia: como expressar o paralelismo de um grafo e como sincronizar as execues de maneira a obter-se determinismo na execuo do programa. A seguir sero apresentados mecanismos de expresso do paralelismo e o

51

captulo seguinte ser dedicado aos mecanismos de sincronizao de processos.

3.3 Especificao de Concorrncia


Construes fork e join [Dennis and Van Horn, 1966; Conway, 1963] As primitivas fork/join especificar concorrncia A primitiva fork v inicia um novo processo que comea a execuo na instruo com o label v. O novo processo compartilha o espao de endereamento do processo criador. O processo que efetuou a chamada fork e o processo criado continuam a execuo em paralelo. A figura a seguir ilustra a operao fork. foram as primeiras notaes de linguagem para

52

Na figura acima, o processo P0 executa a operao fork, criando o processo P1, dividindo a computao em duas. Uma que ser executada pelo processo P1 e a do processo P0, que continua em paralelo com o processo criado. Considerando os comandos: S0: a = 5 ; b = a + 7 ; S1: c = 3 ; d = c + 2 ; S2: e = 4 ; f = e / 2 ;

A execuo paralela com o comando fork pode ser obtida com

fork L0 ; fork L1 ; S0 ; go to Fim ; L0: S1 ; go to Fim ; L1: Fim: S2 ; exit ;

A execuo comea com o processo que executar o comando S1, que inicialmente executa a operao fork L0; que cria um novo processo que comear sua execuo no comando com o label L0 e que executar o comando S1. Aps a execuo desta primitiva, o programa possui dois
53

processos que executam em paralelo. O processo que executa o comando S1 continua a execuo no comando seguinte e executa uma nova operao fork para criar um novo processo, que inicia no label L1 e executar o comando S2. Existir, portanto, dependendo da velocidade de execuo, trs processos em execuo paralela, S1, S2 e S3. A figura a seguir ilustra o fluxo de execuo do programa acima.

S0

fork L0

S0

S1

fork L1

S0

S2

Fim

Programa paralelo com uso de fork

54

Existem situaes nas quais um processo deve continuar somente aps um conjunto de processos terem terminado. Por exemplo, no programa apresentado acima, se for necessria a execuo de um comando S3, que calcula a soma de todas as variveis calculadas por S0, S1 e S2, o mesmo somente poder ser executado ao final da execuo destes comandos. A instruo
join counter, addr definida por Conway, decrementa counter e o compara com zero. Se o valor for igual a zero, o processo executa a partir do endereo addr, caso contrrio termina. Desta forma, a operao join combina vrias execues concorrentes em uma. Cada processo participante do grupo de processos deve requisitar um join. O ltimo processo a executar o join continua, os demais, como o valor de counter maior que zero, terminam (figura abaixo).

55

join (counter, addr )

counter = counter -1 ; counter != 0 quit =0 go to addr

Construo join

Como vrios processos podem chamar concorrentemente a operao join, a mesma indivisvel. Na construo join, um processo termina sua execuo quando o valor da varivel count diferente de 0. Isto feito com uma operao quit, que destri o processo que a executa. O exemplo a seguir ilustra o uso das construes fork/join. O programa calcula a soma dos elementos de dois vetores, A e B, e est programado em uma pseudo-linguagem C. Um processo calcula a soma dos elementos do vetor A, outro dos elementos do vetor B e o ltimo processo a terminar a soma, calcula a soma total. dever ser atmica. Isto significa que as operaes que decrementam a varivel e a que faz o teste devem ser executadas de maneira

56

main() { int FIM, L0, L1, count = 2 ; int soma0=0, soma1=0, somatotal=0 ; int N = 100 ; int i, j ; int A[1, N], B[1, N] ; fork L0 ; for (i=0; i<N; i++){ soma0 = soma0 + A[i] ; } go to L1 ; L0: for (j=0; j<N; j++) Soma1 = soma1 + B[j] ; L1: join count, L2 ; L2: somatotal = soma0 + soma1 ; }

No programa acima criado um processo, que executa a partir do label L0, a soma do vetor B. O processo que efetuou a chamada fork soma os elementos do vetor A. Para o primeiro processo que executar a operao join o valor de count ser maior que zero e o mesmo no executar a partir do rtulo FIM, executando, portanto, a operao quit, que o termina. O outro processo, conseqentemente, calcular a soma total dos elementos dos dois vetores. As operaes fork/join podem aparecer em qualquer trecho de cdigo, podendo fazer parte de loops e de comandos condicionais. Programas escritos desta forma se tornam difceis de ser entendidos, pois necessrio saber quais procedimentos sero executados para saber os processos que iro ser criados no programa. Porm, se usados de forma disciplinada representam um excelente mecanismo de criao dinmica de processos. O sistema operacional Linux implementa uma variao da primitiva fork apresentada anteriormente. A construo fork no sistema Linux possui a seguinte forma: 57

id = fork() ; As caractersticas do fork no Linux so as seguintes: Duplica o processo que executa a chamada e os dois executam o mesmo cdigo; Cada processo tem seu prprio espao de endereamento, com cpia de todas as variveis, que so independentes em relao s variveis do outro processo; Ambos executam a instruo seguinte chamada de sistema; id, no retorno da chamada, contm, no processo pai, o identificador do processo filho criado; Para o processo filho o valor da varivel id ser zero; Pode-se selecionar o trecho de cdigo que ser executado pelos processos com o comando if; No existe o comando join (a sincronizao feita com wait()), que bloqueia o processo que a executa at que um processo filho (criado pelo que executou a operao wait) termine.

Exemplo de programa com fork no Unix

#include <stdio.h> #include <sys/types.h> #include <signal.h>

58

int main() { int id ; id = fork () ; if (id != 0) { printf(Eu sou o pai\n) ; wait(0) ; } else printf(Eu sou o filho\n)

No programa acima, escrito em C, criado um processo com a chamada da primitiva id = fork (). Para o processo pai, o que executou a chamada, o valor retornado na varivel id o nmero de criao do processo filho, que o identifica no sistema, e para o processo filho o valor da varivel id zero. Desta forma, para o processo pai o teste if (id != 0) verdadeiro e so executados os comandos printf e wait (0), que o bloqueia at que o processo filho termine. Como para o processo filho o teste do if falso, ele executa printf e a seguir termina. O seu trmino desbloquear o processo pai, que estava bloqueado no wait, que tambm terminar. O grafo a seguir P0

P1

P2 Grafo com trs processos

59

representando trs processos diferentes, indicando que P1 executa depois que P0 terminar e que P2 executar somente aps o trmino de P1, pode ser programado com fork no Linux da seguinte forma:
#include <stdio.h> #include <sys/types.h> #include <signal.h>

int main () { int id0, id1 ; // cdigo de P0 id0 = fork () ; if (id0 != 0) exit (0) ; // P0 termina else{ //cdigo de P1 id1 = fork () ; if (id1 != 0) exit (0) ; //P1 termina else { // cdigo de P2 } } }

No programa acima utilizada a primitiva exit (), que termina o processo que a executa, liberando os recursos alocados ao processo (memria, etc.). O grafo de processos a seguir

60

P0

P1

P2

P3 Grafo de processos com quatro processos

representando quatro processos, com fork no Linux pode ser programado como apresentado a seguir:
#include <stdio.h> #include <sys/types.h> #include <signal.h>

int main () { int id0, id1, id2 ; // cdigo de P0 id0 = fork () ; if (id0 != 0) { id1 = fork () ; if (id1 != 0) exit (0) ; // P0 termina else { // cdigo de P2 } } else{ //cdigo de P1 id2 = fork () ; if (id2 != 0) exit (0) ; //P1 termina else { // cdigo de P3 } } }

61

Construes CoBegin CoEnd Esta construo, tambm chamada ParBegin ParEnd, foi criada por Dijkstra em 1968. uma construo de mais alto nvel, se comparada a construo fork, e mais fcil de ser utilizada. A forma geral a seguinte:

cobegin S1; S2; .. Sn; coend;

Quando o cobegin executado criado um processo para executar cada um dos comandos entre o cobegin e o coend. Baseado na linguagem Algol, os comandos entre o cobegin/coend podem ser simples ou compostos. Comandos compostos so delimitados por begin/end. Quando todos estes processos terminarem, o coend executado, e o processo pai, o que executou o cobegin, recomea a execuo. Assim, todos os processos entre o cobegin e o coend so executados concorrentemente. A figura a seguir ilustra a construo cobegin/coend.

62

cobegin

P1

P2

Pn

coend

P Construo cobegin/coend

O exemplo a seguir Cobegin a (x, y, z) ; b (i, j) ; begin c (r, s) ; d ( g, h) ;

63

end Coend formado por dois comandos simples, a chamada do procedimento a (x, y, z) e do procedimento b (i, j) e por um comando composto, delimitado por begin/end, contendo as chamadas de procedimento c (r, s) e d ( g, h). Os comandos simples sero executados em paralelo com o comando composto. No comando composto, sero executadas seqencialmente as chamadas dos procedimento c e d. A figura a seguir ilustra a execuo deste comando concorrente.

P0

Cobegin

a(x, y, z)

b(i, j)

c ( r , s) d (g , h )

Coend P0

64

O programa a seguir utiliza comando concorrente para fazer a cpia de um arquivo f para um arquivo g.

FILE f, g ; char buffer0[4096], buffer1[4096] ; int i, j, k ; int main() { i = read (f, &buffer0, 4096) ; while (i > 0) { for (j=0; j<i; j++) buffer1[j] = buffer0[j] ; cobegin k = write (g, &buffer1, i) ; i = read (f, &buffer0, 4096) ; coend ; } }

No programa acima, enquanto um processo grava os i bytes no arquivo g, um outro processo faz a leitura dos prximos i bytes do arquivo f. Estas operaes se repetem at que a cpia se complete.

Primitivas para manipulao de processos O sistema operacional deve oferecer primitivas que permitam criao, destruio, bloqueio e sinalizao de processos. Para a criao de processos as primitivas so do tipo cobegin/coend e fork, apresentadas anteriormente. Na primitiva fork, o processo pai executa concorrentemente com o processo filho. Com cobegin/coend o processo pai fica bloqueado no coend at que todos os processos concorrentes criados na construo cobegin/coend terminem. Com

65

relao aos dados, na implementao Linux do comando fork o processo filho uma cpia do processo pai e, a partir do fork, compartilham um subconjunto das variveis (arquivos abertos, ...).

Trmino de processos Um processo termina em trs situaes: Quando acaba a execuo de seu ltimo comando; Em circunstncias especiais um processo pode acabar antes de executar o seu ltimo comando (ex. endereo de um vetor fora dos limites); Um processo pode causar a morte de outros processos com primitivas especiais (ex. um processo est em um loop eterno e necessita ser terminado). As primitivas que implementam o trmino de processos so: exit () o O processo que a executa termina normalmente. Seus recursos so liberados pelo S.O. abort (id), kill (id) o id a identificao do processo terminar; o abort e kill so chamadas pelo pai do processo id; o para poder matar, o pai necessita conhecer a identidade do filho, que retorna na operao de criao. O exemplo a seguir ilustra o uso da primitiva kill no sistema operacional Linux.
#include <stdio.h> #include <sys/types.h>

66

#include <signal.h> int main() { int id ; id = fork () ; if (id != 0) { printf(Eu sou o pai\n) ; sleep(5) ; kill (id, SIGKILL) ; } else{ printf(Eu sou o filho\n) while(1) ;

} } No programa acima o processo pai, aps o fork, executa a primitiva sleep(5), que o bloqueia durante cinco segundos. Transcorrido este tempo, o processo filho, que estava em um loop eterno (while(1)) eliminado com a primitiva kill (id, SIGKILL), executada pelo processo pai.

3.4 Processos leves (Threads)


Threads so processos leves, definidos para permitir paralelismo em um programa de aplicao. Um programa com mltiplos pontos de execuo possui tantas threads de execuo quantos forem estes pontos. As threads possuem sua prpria pilha de execuo e o seu prprio program counter, cada uma roda um cdigo seqencial, definido no programa de aplicao (processo pesado) no qual foram definidas, compartiham o uso do processador, podem criar processos (threads) filhos e compartilham o mesmo espao de endereamento (dados globais) do processo pesado ao qual pertencem. Portanto, quando uma

67

thread altera um valor compartilhado, todas percebem esta mudana e os arquivos abertos por uma thread so disponvel as outras threads do mesmo processo pesado. Para manter a coerncia dos dados, mecanismos de sincronizao devem ser utilizados pelo programador. As threads sofrem transio entre os estados existe estado ready, running, blocked. No

swapped , isto , uma thread no pode, durante a sua

execuo, ser retirada da memria principal e gravada em disco para liberar memria e permitir que um novo programa possa ser carregado para execuo. A operao de swap no existe para uma thread, somente para todo o processo pesado. Outra caracterstica que a terminao do processo pesado termina todas as threads no processo.

Implementao de Threads Threads podem ser implementadas por bibliotecas. Existem trs modelos bsicos para a implementao das bibliotecas de threads , que identificam a forma de representao das threads no sistema operacional. Os modelos so: N:1 (many-to-one), 1:1 (one-to-one), e M:N (many-to-many).

Modelo N:1 Neste modelo, a implementao feita a nvel de usurio, por uma biblioteca que implementa os procedimentos de gerenciamento de threads. Estes procedimentos incluem primitivas para criar, destruir, bloquear, etc., alm de implementarem os algoritmos de escalonamento. Desta forma, a gerenciamento de threads realizado pela aplicao (biblioteca de threads). O ncleo do sistema no conhece threads, executa o escalonamento do processo pesado no qual as threads foram definidas. O tempo de processador do processo pesado distribudo, pelo escalonador de threads da biblioteca de threads, entre as diferentes threads que fazem parte da aplicao. Assim, o chaveamento de 68

threads no requer privilgios do modo kernel, sendo especfico da aplicao. As principais caractersticas das bibliotecas de threads a nvel usurio so: Quando uma thread faz uma chamada de sistema, todo processo pesado ser bloqueado. No entanto, para a biblioteca de threads, a thread rodando estar ainda no estado running; O estado das threads independente do estado do processo pesado.

Vantagens e desvantagens de threads a nvel de usurio Vantagens Chaveamento de threads no envolve o kernel, no troca de modo de execuo (usurio/sistema); Escalonamento pode ser dependente da aplicao: escolha de algoritmo adequado a cada aplicao; Pode rodar em qualquer SO, bastando para tal a instalao da biblioteca.

Desvantagens Maioria das chamadas de sistema so bloqueantes e o kernel bloqueia todo processo pesado, apesar de outra thread do processo poder continuar; O ncleo s associa processos pesados a processadores. Duas threads do mesmo processo pesado no podem rodar em processadores diferentes.

Modelo 1:1 Neste modelo, a gerncia de threads feita no ncleo do sistema. Assim, a cada primitiva de manipulao de threads corresponde uma rotina de biblioteca que empacota os parmetros da chamada e executa uma troca de contexto, 69

passando a execuo para o ncleo do sistema operacional. O ncleo mantm informaes de contexto sobre threads e processos pesados. Desta forma, as operaes de criao, destruio, etc. de threads so realizadas pelo sistema operacional. A cada thread no programa de aplicao corresponder uma thread no ncleo. Portanto, o chaveamento de threads envolve o ncleo.

Vantagens e desvantagens da implementao de threads no ncleo do sistema Vantagens O ncleo pode escalonar simultaneamente vrias threads do mesmo processo pesado em diferentes processadores; O bloqueio a nvel de thread e no de processo pesado; As rotinas do SO podem ser tambm multithreaded.

Desvantagens Chaveamento de threads dentro do mesmo processo pesado envolve o ncleo o que representa um impacto significativo no desempenho do sistema.

Modelo M:N Neste modelo, cada processo de usurio pode conter M threads, que so mapeadas em N threads sistema. O gerenciamento de threads realizado a nvel usurio, assim como o escalonamento e a sincronizao, sendo que o programador ajusta o nmero de threads sistema que sero utilizadas para mapear as threads usurio. Existe portanto uma distino entre threads do usurio e threads do sistema. As threads do usurio so invisveis ao SO e oferecem a interface de programao. As threads do sistema identificam uma

70

unidade que pode ser escalonada em um processador, e suas estruturas so mantidas pelo ncleo. pthreads (POSIX Threads) A biblioteca pthreads (POSIX Threads) define uma interface de programao que permite o desenvolvimento de programas C, C++ utilizando threads. Com pthreads, a criao de uma thread feita com a primitiva int pthread_create( pthread_t *thid, const pthread_attr_t *atrib, void *(*funcao), void *args ); que pode aparecer em um bloco qualquer de comandos. O parmetro thid, do tipo pthread_t, contm, no retorno da chamada, o identificador da thread criada, atrib permite ao programador definir alguns atributos especiais (poltica de escalonamento da thread., escopo de execuo da thread, isto , modelo 1:1 ou modelo N:1, etc.). Se for passado o argumento NULL, so utilizados os atributos default. args contm o endereo de memria dos dados passados como parmetros para a thread criada. Se a operao falha, a thread no criada e o valor retornado indica a natureza do erro: EAGAIN: O sistema no possui os recursos necessrios para criar a nova thread. EFAULT: o nome da funo a ser executada (thread) ou attr no um ponteiro vlido. EINVAL: attr no um atributo inicializado. No caso de sucesso da operao retornado o valor 0. Em C/C++, o conjunto de instrues a ser executado por uma thread definido no corpo de uma funo. A primitiva pthread_join( pthread_t thid, void **args ); 71

permite a uma thread

se bloquear at que a thread identificada por thid

termine. A thread pode retornar valores em args: 0 em caso de operao bem sucedida, um valor negativo em caso de falha, e um valor de retorno calculado pela thread. Se o programador no deseja valor de retorno, pode passar NULL como segundo argumento. O programa a seguir, escrito em C, demonstra o uso destas primitivas para a implementao de um programa concorrente.

#include <pthread.h> #include <stdio.h>

void * Thread0 () { int i; for(i=1;i<100;i++) print(" Thread0 - %d\n",i); } void * Thread1 () { int i; for(i=100;i<200;i++) print(" Thread1 - %d\n",i); } int main(){ pthread_t t0, t1; int ret0, ret1; ret0 = pthread_create(&t0, NULL, Thread0,NULL) ; ret1 = pthread_create(&t1, NULL, Thread1,NULL) ; pthread_join(t0,NULL); pthread_join(t1,NULL); printf("Main ....\n"); }

O programa acima formado por trs threads, uma thread to, que executa o cdigo da funo Thread0 que imprime os valores entre 0 e 99, uma thread t1, que executa o cdigo da funo Thread1 que imprime os valores entre 100 e

72

199, e a thread main, que executa o cdigo da funo main do programa. A execuo comea na thread main, que cria a thread to, com a chamada da primitiva pthread_create. A partir da execuo desta primitiva, a thread main e a thread criada passam a compartilhar o uso do processador. A seguir, a thread main cria a thread t1 (passando ento a existir trs threads em execuo) e se bloqueia, com a primitiva pthread_join(t0,NULL), a espera que a thread t0 termine. Aps o trmino da thread t0, a thread main se bloqueia, com a operao pthread_join(t1,NULL), e ser acordada com o trmino da thread t1. O uso da primitiva pthread_join indispensvel, pois impede que a thread main continue a execuo e termine, pois as threads definidas em um processo pesado so eliminadas se o processo pesado termina, o que ocorre com o trmino da thread main.

Exerccios
1. Compare o uso de threads e de processos pesados no desenvolvimento de programas concorrentes. 2. Faa o grafo de precedncia do programa concorrente apresentado a seguir. count1 = 2 ; count2 = 2 ; s1 ; fork L1 ; s2 ; s4 ; s7 ; go to L4 ; L1: s3 ; fork L2 ; s5 ; go to L3 ; L2: s6 ; L3: join count2 ; s8 ; L4: join count1 ; s9 ;

73

3. Considerando os comandos apresentados a seguir, faa o grafo de precedncia e escreva o programa concorrente com o uso de fork/join. a = b + c ; (s0) d = e + f ; (s1) g = d + k ; (s2) h = g + a ; (s3) m = n + h ; (s4) x = m + h ; (s5) y = x + g ; (s6) z = y + 3; (s7) 4. Defina um conjunto de no mnimo 8 comandos (ex. S0: a = b+2 ;), construa o grafo de predecncia e escreva o programa correspondente, com o uso de fork/join. 5. Fale sobre as possibilidades de implementao de threads, relacionando vantagens/desvantagens de cada modelo. 6. Descreva as aes executadas pelo sistema operacional Linux na execuo da primitiva fork. 7. Defina um grafo com no mnimo 5 processos e o implemente com fork no sistema operacional Linux.

Bibliografia

74

4. Escalonamento
Conceitos Bsicos. Algoritmos de escalonamento. Escalonamento de processos em mquinas paralelas. Escalonamento no Linux e Windows NT.

4.1 Conceitos Bsicos


Em sistemas com multiprogramao o uso da CPU compartilhado entre os diferentes programas em execuo, criando uma iluso de paralelismo (pseudo-paralelismo). Isso ocorre porque o tempo do processador distribudo entre os processos que esto em execuo. Para o usurio como se cada processo tivesse a sua prpria CPU, porm com uma velocidade menor do que a CPU real. Assim, pode-se imaginar que cada processo tem sua prpria CPU virtual. Nos sistemas uniprocessador, existe um processo running (o que detm o processador) e os demais processos aptos a executar esperam pela CPU em uma fila (a ready list) que contm os processos aptos a rodar. O sistema possui ainda outras filas: filas de dispositivos: contm os processos esperando I/O; filas de eventos: contm os processos bloqueados a espera de eventos (ex. passagem de tempo).

Process Control Block Os processos so representados no sistema por um registro descritor, que mantm as informaes referentes ao processo. Informaes tpicas so: estado do processo: ready, running, blocked, etc.;

75

program counter; registradores da CPU; informao de escalonamento (dependem do algoritmo - prioridades, ponteiros para filas, etc.);

Informao para gerncia de memria: valor de registradores base e limite, registradores que apontam para a tabela de pginas, etc.;

Informao de contabilizaro: tempo de CPU utilizada, limites, etc.; informao de estado de I/O: lista de dispositivos alocados ao processo, arquivos abertos, etc.

O sistema operacional gerencia uma tabela de descritores, cada um descrevendo um processo em execuo. Quando um processo submetido, um registro descritor criado e incorporado a tabela de descritores. Quando o processo termina, seu registro descritor eliminado. As filas existentes no sistema (ready list, filas de perifricos, etc.) so igualmente gerenciadas pelo sistema operacional. As figuras abaixo exemplificam a fila de processos aptos rodar, na qual esto os processos 0,5 e 9, a fila do disco0, com os processos 7 e 13 e a fila do disco1, com o processo 12.

76

Ready List Ult

Prim

Desc0

Desc5

Desc9

Disco 0 Prim Desc7 Desc13

Ult

Disco 1 Prim Desc12

Ult

Filas gerenciadas pelo Sistema Operacional

Escalonamento da CPU 77

Com multiprogramao vrios processos residem na memria e a CPU compartilhada pelos mesmos. A execuo de um programa uma seqncia de execuo e espera por I/O. Assim, para otimizar o uso da CPU, quando o programa faz I/O a CPU entregue a outro processo. Escalonamento a troca da CPU entre os vrios programas na memria prontos para executar. Os escalonadores so processos do sistema operacional que

implementam a Poltica de Escalonamento. Podem ser de longo termo e de pequeno termo.

Escalonadores de Longo Termo Considerando-se, por exemplo, um sistema operacional do tipo Batch, no qual os processos submetidos pelos usurios so colocados em uma lista de execuo, no disco, os escalonadores de longo termo selecionam processos desta lista para serem carregados na memria para execuo. Uma vez na memria, o processo inserido na ready list, de onde ser selecionado pelo escalonador de pequeno termo para ganhar o processador. Escalonadores de longo termo normalmente no existem em sistemas interativos (Unix, Dos, Windows, ...).

Escalonadores de Pequeno Termo Os escalonadores de pequeno termo (Escalonadores da CPU) selecionam um processo, entre os aptos (que esto na ready list), e o coloca para rodar. A diferena entre estes dois tipos de escalonadores a freqncia de execuo. O escalonador de pequeno termo executa muito mais freqentemente que o de longo termo. Por exemplo, a cada 20 mseg o escalonador de pequeno termo seleciona um processo para execuo, enquanto que o de longo termo executa ao trmino de um processo, para colocar um novo na memria.

78

Dispatcher O dispatcher o componente do escalonador responsvel pela entrega da CPU para o processo selecionado pelo Escalonador de Pequeno Termo (Escalonador da CPU). Para tal executa as seguintes aes: carrega os registradores de uso geral do processo selecionado (armazenados na pilha ou no descritor do processo) nos registradores de mquina (restaurao de contexto); carrega o Program Counter (dispara a execuo).

4.2 Algoritmos de escalonamento


Os algoritmos implementam as polticas de escalonamento. Os objetivos dos algoritmos so:

Minimizar o tempo de resposta; Maximizar o nmero de processos executados por unidade de tempo; Distribuir uniformemente o tempo de CPU.

Algoritmos de Scheduling A seguir sero apresentados os principais algoritmos de escalonamento. Algoritmo 1: Fila de processos (First-Come-First-Served)

Neste algoritmo, o primeiro processo que requisita a CPU o primeiro que a recebe. 1. Processo pronto para executar entra no final da lista ready; 2. Quando a CPU liberada alocada para o primeiro da lista. 79

Prim P3 Ult Ready List com FCFS 12 P7 2 P5 4

A figura acima mostra trs processos (P3, P7 e P5), com seus respectivos tempos de execuo, inseridos na ready list em ordem de chegada. Assim, a execuo de P5 comeara aps o trmino de P3 e P7, ou seja, ficar na fila 14 unidades de tempo. O tempo mdio de execuo de 6 unidades de tempo. Este algoritmo inadequado para sistemas interativos, pois processos CPU bound, isto , que possuem muita necessidade de processamento e pouca de operaes de entrada e sada, ao ganharem o processador o monopolizam por muito tempo. Os demais processos na fila so retardados e o tempo de resposta se torna invivel a um sistema em que a resposta deve ser imediata. No exemplo acima, os tempos de espera na fila so:

P3: 0 P7: 12 P5: (12 + 2) = 14

Algoritmo 2: Menores processos primeiro (SJF Shortest Job First) O SJF associa a cada processo o seu prximo tempo de ocupao de CPU. Quando a CPU esta livre atribuda ao processo que ir utilizar a CPU por 80

menos tempo. Este algoritmo baseado em prioridades, pois cada processo tem uma prioridade associada (prximo tempo de CPU) e a cpu alocada ao processo de maior prioridade (o que necessita de menor tempo).

Prim P7 Ult Ready List com SJF 2 P5 4 P3 12

Para este algoritmo, os tempos de espera na fila so: P3: (2+4) = 6 P7: 0 P5: 2 Em relao ao algoritmo anterior, o tempo de espera na fila menor. O processo que fica mais tempo na fila espera 6 unidades de tempo, enquanto que no FCFS o maior tempo de espera de 14 unidades de tempo. O problema do SJF determinar prximo tempo de CPU para cada processo. Uma soluo adotada fazer uma anlise histrica da execuo de cada processo. Com base nesta anlise, determinar o prximo tempo de uso de CPU para cada processo, e coloc-lo na ready list na posio correspondente a este valor (esta prioridade). Nos algoritmos baseado em prioridades existe um campo de variao (0..N) que indica a prioridade do processo. Em alguns sistemas 0 a maior, 81

outros 0 a menor. Nos algoritmo baseado em prioridades um problema que pode surgir o de postergao indefinida de processos com baixa prioridade. Para solucion-lo, uma possibilidade de tempos em tempos incrementar a prioridade dos processos de baixa prioridade, garantindo, desta forma, suas execues em um tempo finito. Outro aspecto importante a chegada na ready list de um processo com prioridade mais alta do que a do processo que est rodando. As alternativas so: e) Um processo chegando na fila ready tem sua prioridade comparada com a do processo que est rodando. Se for maior, ganha a cpu, caso contrrio fica na fila. Neste caso, diz-se que o algoritmo preemptivo. f) Um processo chegando na fila ready sempre colocado na fila, de acordo com a sua prioridade. Algoritmo no preemptivo. Em sistemas de tempo real, nos quais os tempos de resposta so muitas vezes fundamentais para alguns processos, os algoritmos devem ser preemptivos.

Algoritmo 3: Round-Robin Neste algoritmo, a lista de processos aptos a executar uma fila circular e existe um tempo mximo que o processo pode ficar com o processador. O funcionamento do algoritmo o seguinte: Pegar o primeiro processo da ready list; O processo executa por uma fatia de tempo, preemptado e reinserido no final da ready list; O primeiro processo da ready list selecionado e ganha o processador. 82

Prim P7 Ult Ready List com Round Robin 6 P5 4 P3 12

Supondo que a fatia de tempo seja de 2 unidades de tempo, o processo P7 ganhar o processador, executar por uma fatia de tempo e ser colocado no final da ready list. O processo P5 ganhar o processador, executar por uma fatia de tempo e ser colocado no final da ready list, aps o processo P7. O processo P5 sai da redy list aps duas execues e o processo P7 aps 3 execues. Mesmo restando somente o processo P3 na ready list e faltando ainda trs execues, o mesmo executar uma fatia de tempo e ser inserido como ltimo na ready list. Como ser tambm o primeiro, ganhar novamente o processador. Isto significa que a ao do escalonador ser sempre a mesma, independentemente do nmero de processos na ready list. Este algoritmo adequado aos sistemas interativos, pois evita que um processo monopolize o uso do processador. contexto. Este tempo depende: Da velocidade de memria; Do nmero de registradores; Da existncia de instrues especiais. Por exemplo, uma instruo que permita mover o valor de todos os registradores para o descritor do processo; Tempos tpicos de salvamento/restaurao de contexto variam de 10-100 microsegundos. Um outro problema para na implementao deste algoritmo a 83 Um aspecto a considerar o overhead determinado pelo tempo salvamento de contexto e de restaurao de

definio do quantum. Um quantum muito grande degenera o algoritmo, aproximando-o do algoritmo de fila (FCFS). Quantum muito pequeno aumenta o tempo gasto com troca de contexto. Valores comuns de time slice variam de 10100 miliseg.

Algoritmos que utilizam Mltiplas filas Uma outra soluo a ser empregada a utilizao de mltiplas filas de escalonamento. Estes algoritmos possuem as seguintes caractersticas: Os processos so classificados em grupos; Existe uma fila para cada grupo; Cada fila pode ter seu prprio algoritmo; Uma fila pode ter prioridade absoluta sobre as demais filas com prioridades menores. Para evitar o problema de postergao indefinida de uma fila, pode existir uma fatia de tempo atribuda a cada fila. Desta forma, assegura-se que processos em filas de baixa prioridade ganhem o processador. Uma alternativa a este algoritmo a existncia de mltiplas filas com reavaliao. Neste caso, os processos se movem entre as filas, variando portanto as prioridades. Nestes algoritmos, deve ser definido o nmero de filas, critrios para movimentar processos para filas de mais alta prioridade, critrios para movimentar processos para filas de mais baixa prioridade e critrios para determinar em qual fila o processo deve iniciar.

84

4.3 Escalonamento de Processos em Mquinas Paralelas


As arquiteturas paralelas do tipo MIMD [Flyn 1972] so compostas por processadores que operam de forma independente. Dois tipos de mquinas, na classificao de Flyn so: mquinas paralelas com memria comum e mquinas paralelas com memria distribuda. Com memria comum, existe uma memria global que pode ser acessada por qualquer processador, figura a seguir.

P0

P1

Mquina Paralela com Memria Comum

A figura acima exemplifica uma mquina paralela com memria comum, formada por quatro processadores, que compartilham uma memria global. Uma mquina sem memria comum mostrada na figura a seguir.

P0

P1

P2

Mquina Paralela Sem Memria Comum

airmeM

airmeM

labolG airmeM
P2 P3

airmeM

airmeM

P3

85

Na figura acima, cada processador possui a sua memria e no pode acessar a memria de outro processador.

Escalonamento em sistemas com memria compartilhada Os sistemas com memria compartilhada, podem possuir na memria comum uma nica fila de processos aptos rodar, compartilhada pelos processadores. O conjunto de processadores que compartilham memria ficam sob o sob controle de um nico sistema operacional. Os processadores so tratados como recursos e o sistema operacional associa processos a processadores, sob demanda, isto , sempre que um processador fica livre o sistema operacional lhe atribui um processo. Esta associao pode ser esttica ou dinmica. esttica quando o processo roda no mesmo processador e dinmica quando em tempos diferentes o processo pode ocupar diferentes processadores. As abordagens podem ser mestre/escravo, mestre flutuante e simtrico. Mestre-escravo: As funes do kernel rodam sempre em um processador, os demais processadores rodam somente ao mestre Vantagens o Simples de projetar e implementar; o Permite execuo paralela de um nico processo. Desvantagens o serializa as chamadas de sistema porque somente o mestre as executa; o O mestre normalmente no fica com muita carga; processos de usurio. O mestre faz escalonamento e se o escravo precisa servio (chamada de sistema), faz pedido

86

o O mestre pode se tornar um gargalo o a falha do mestre para todo o sistema. Mestre flutuante: o sistema operacional inteiro tratado como uma seo crtica. Somente um processador por vez executa o cdigo do sistema operacional. Vantagens: o Todos os processadores so completamente utilizados; o Permite execuo paralela de um processo . Desvantagens o O gargalo do mestre continua.

Configurao simtrica: o sistema operacional pode ser acessado por mltiplos processadores simultaneamente, sendo que existem sees crticas para acessar os dados compartilhados. Vantagens: o Permite execuo paralela de uma nica task; o Configurao mais verstil. Desvantagens: o Mais difcil de projetar e implementar o Requer kernel reentrante o Sees crticas escritas diferentemente o Muitas chamadas de sistema executadas concorrentemente

87

Escalonamento em sistemas sem memria compartilhada

Uma aplicao paralela, classificada quanto ao nmero de processos, como esttica ou dinmica. Em uma aplicao esttica o nmero de processos conhecido no incio de sua execuo e no se modifica at o trmino do processamento. O grafo de processos no se altera. Aplicaes dinmicas so aquelas que o nmero de processos podem variar durante a execuo. No primeiro caso, os processos so alocados aos ns processadores da rede durante a inicializao e permanecem no mesmo n at o final de sua execuo. No ocorre migrao de processos e no so criados novos processos. No segundo caso, a alocao dos processos criados dinamicamente deve ser feita de maneira a garantir um bom desempenho global do sistema (throughput). A carga de trabalho deve ser distribuda de uma forma balanceada para evitar-se que coexistam no sistema ns ociosos e ns sobrecarregados. Pode-se utilizar a migrao de processos para obter este balanceamento de carga. Em [Gozinsky] apresentada uma classificao dos algoritmos de escalonamento. De acordo com esta classificao, um algoritmo global pode ser esttico ou dinmico. Ele esttico quando o processador onde o processo ser executado definido antes da execuo. Depois de realizada a alocao o processo permanece neste processador at o final de sua execuo. Nos algoritmos dinmicos a deciso do processador feita medida que os processos so criados. Para melhorar o balanceamento de carga, pode ocorrer a migrao de processos. Outro importante aspecto da classificao relacionado escolha do processador onde ser executado o processo. Em algoritmos centralizados a informao sobre a carga dos processadores mantida em um processador do sistema, e a deciso de alocao tambm centralizada. Em algoritmos distribudos a informao sobre a carga dos processadores distribuda ao

88

longo dos processadores do sistema, a deciso de alocao ocorre tambm de forma distribuda. Quanto s decises, elas podem ser cooperativas quando envolvem os outros processadores do sistema ou no cooperativas quando no envolvem os outros ns. Os algoritmos so constitudos de quatro elementos bsicos, que implementam a poltica de informao, a poltica de transferncia, a poltica de localizao e a poltica de negociao. A poltica de informao responsvel pelo armazenamento dos dados relativos a carga dos processadores. A poltica de transferncia responsvel pelas tarefas de transferncia entre processadores. A poltica de localizao determina em que processador do sistema o processo ser criado ou para que processador o processo ser migrado. A poltica de negociao representa a interao entre os processadores durante o processo de deciso.

4.4 Escalonamento no Linux e no Windows 2000/XP


A seguir sero apresentados os algoritmos de escalonamento utilizados nos sistemas operacionais Linux e Windows 2000/XP.

Escalonamento no sistema operacional Linux Em seu desenvolvimento, os requisitos definidos para o escalonador do Linux foram: Apresentar boa performance em programas interativos, mesmo com carga elevada; Distribuir de maneira justa o tempo da CPU; Ser eficiente em mquinas SMP; Possuir suporte para tempo real. 89

Em relao ao primeiro requisito, tradicionalmente se classifica os processos em I/O bound e CPU bound. Por exemplo, um editor de textos tipicamente um processo I/O bound, pois se caracteriza pelo altssmo nmero de operaes de entrada e sada e pela interao com o usurio, podendo tambm ser classificado como interativo. Processos CPU bound, ao contrrio, usam muita CPU e fazem poucas operaes de I/O. De maneira a oferecer um bom tempo de resposta, o Linux favorece os processos interativos, em relao aos processos CPU bound. Cada processo no Linux possui uma prioridade, que recalculada dinamicamente. O escalonador entrega a CPU para o processo que possui a maior prioridade. O escalonador do Linux preemptivo. O kernel verifica a prioridade do processo que passa para o estado running. Se maior do que a do processo que estava rodando, o kernel chama o escalonador, que ir selecionar um novo processo para execuo (o que se tornou running). O Linux considera dois tipos de processos, cujas caractersticas definem o algoritmo de scheduling usado: processos interativos(time-sharing) e tempo real. Para os processos interativos o algoritmo o Round Robin. Para processos de tempo real os algoritmos so FCFS e Round Robin. Processos de tempo real possuem prioridade sobre todos os demais processos. Se existe um processo de tempo real para rodar, ele sempre ganha o processador primeiro. Processos de tempo real Round Robin possuem uma prioridade, e o escalonador escolhe o processo de maior prioridade. Processos FCFS executam at terminarem ou at se bloquearem. Nas verses que antecederam a 2.6, o escalonamento do Linux sofria alguma justificadas crticas: a) Aumento do tempo de execuo do escalonador proporcionalmente ao aumento do nmero de processos no sistema; b) Uma ready list global em mquinas SMP.

90

O escalonador deve selecionar o processo de maior prioridade para entregar o processador. Para fazer isso, mantm uma fila de processos, cada um possuindo uma prioridade, baseada em uma prioridade bsica (Nice) e em seu comportamento em tempo de execuo. Uma vez selecionado, o processo ganha a CPU por uma fatia de tempo (timeslice). Quando o timeslice chega a zero, o processo marcado como expirado. O escalonador, quando chamado, seleciona o processo no expirado com a maior prioridade. Quando todos os processos estiverem com seu timeslice expirado, o escalonador recalcula a prioridade de todos e ento seleciona o prximo a rodar. Este reccculo de prioridades representa tempo de execuo para o escalonador. Aumentando o nmero de processos no sistema, aumenta o tempo necessrio para o escalonador recalcular as prioridades. Para aplicaes com um nmero pequeno de processos este tempo no significativo. Para aplicaes com um nmero muito grande de processos, este tempo poderia penalizar enormemente o desempenho do sistema. Referente ao segundo aspecto das crticas ao escalonador do Linux, nas verses anteriores a 2.6, a existncia de uma ready list global nas mquinas SMP, os problemas so de duas naturezas: primeiro a necessidade de acesso a mutuamente exclusivo a ready list por parte dos processadores. Se um processador est acessando a ready list os demais necessitam esperar at que a mesma seja liberada. Para um nmero elevado de processadores este bloqueio dos processadores pode acarretar em uma queda considervel no desempenho do sistema. Segundo, um processo interrompido, por exemplo, porque solicitou uma operao de entrada e sada, quando esta se completa recolocado na ready list, que global, e poder ser executado por um processador diferente daquele no qual estava rodando previamente. Isto acontecendo, dados do processo porventura existentes em caches no podero mais ser usados, provocando uma sobrecarga de processamento, influenciando negativamente na performance.

91

Escalonamento no Kernel 2.6 As principais caractersticas do escalonador do kernel 2.6, tornado pblico no final de 2003, chamado de 0(1) scheduler so: Tempo constante de execuo para selecionar um processo para rodar, independentemente do nmero de processos; Boa performance com programas interativos mesmo com o sistema sobrecarregado; Eficiente em mquinas SMP; Afinidade de processador, com uma fila de aptos para cada processador; Suporte a tempo real. O escalonador do kernel 2.6 possui uma fila de todos os processos prontos para executar. Esta fila implementada por dois arrays, um com os processos ativos, elegveis para rodar e outro expirado, com processos temporariamente inelegveis. Quando um processo termina sua fatia de tempo, colocado na fila dos expirados, e aguarda at que isso acontea com todos os processos do array ativos. Ento, o array expirado se torna ativo, com uma simples troca de apontadores. A figura a seguir esquematiza uma fila de processos aptos. Em mquinas SMP, existe uma fila de aptos para cada CPU.
sotpa ed aliF nP nP 5P 3P 2P 6P 4P 041 edadiroirP 1 edadiroirP 1 edadiroirP oargim ed daerhT sodaripxE sovitA

92

O escalonador possui 140 nveis de prioridade, sendo que quanto menor o nvel, maior a prioridade. Prioridades de 1 a 100 so para processos de tempo real. De 101 a 140 para demais processos de usurio (interativos ou no interativos). Os processos de tempo real podem ser FIFO ou Round Robin, e possuem uma prioridade esttica. Processos FIFO executam at voluntariamente liberarem a CPU. O nvel de prioridade mantido e no so preemptados. Processos Round Robin recebem uma fatia de tempo e executam at terminar esta fatia de tempo. Quando todos os processos de um dado nvel de prioridade tenham terminado uma outra fatia de tempo atribuda e les continuam rodando, no mesmo nvel de prioridade. A prioridade dos processos de usurio a soma de sua prioridade, que o valor de seu nice e seu bonus dinmico de prioridade, que varia de +5 a 5. Nos nveis de prioridade 101 a 140, os processos de usurio possuem uma fatia de tempo de 20 ms. Esgotado este tempo, o prximo processo da fila de mesma prioridade ganha o processador (Round Robin). Para o clculo da prioridade dos processos de usurio, avaliado o seu nvel de interatividade. Os processos so classificados, pelo escalonador, em interativos e no interativos pelaobservao de seu comportamento. Processos interativos so aqueles que ficam bloqueados por longos perodos esperando por I/O, executam rapidamente e ficam novamente esperando por I/O. O escalonador calcula a mdia de tempo bloqueado de um processo e a utiliza para calcular o bnus de prioridade do processo. Assim, os processos so classificados em interativos e no interativos e a idia aumentar a prioridade de processos interativos (I/O bound) e diminuir a prioridade de processos no interativos (CPU bound). Finalmente, em cada processador roda uma thread de migrao, que tem a funo de movimentar processos de um processador para outro, para balancear o uso dos processadores. Como existe uma ready list por processador, aidia evitar que existam processadores ociosos enquanto outros estejam sobrecarregados. A thread de migrao chamada explicitamente, quando o sistema esta desbalanceado, e periodicamente, a cada tick do relgio.

93

Linux I/O scheduler No linux, as operaes de leitura (READ) so sncronas e bloqueantes, porque existe a suposio de que o processo que executou a operao de leitura necessita dos dados para continuar, e as operaes de escrita (WRITE) so assncronas e no-bloqueantes. Por este motivo, as operaes de leitura possuem prioridade em relao as operaes de escrita. Alm disso, as requisies so classificadas, de forma a minimizar a distncia de deslocamento do cabeote do disco. Para evitar postergao indefinida, a cada requisio atribudo um deadline de atendimento. O escalonador do kernel 2.6 implementa duas polticas: deadline scheduler e antecipatrio scheduler(AS) Deadline Scheduler O escalonador atribui a cada processo um tempo limite de atendimento e implementa duas filas: uma fila de READ, com um deadline de 500 ms e uma fila de WRITE, com um deadline de 5 seg. Quando a requisio submetida, inserida na fila apropriada (READ ou WRITE), na posio correspondente a sua requisio. O escalonador dispara as requisies, seguindo a ordem das filas. Se um deadline expira, ento o escalonador dispara as requisies seguindo a ordem da fila, garantindo a execuo das requisies cujo deadline expirou. Esta poltica assegura que as operaes de posicionamento da cabeote (seek) so minimizadas (pela classificao das requisies) e o deadline garante que no haver postergao indefinida de requisies. Outro aspecto importante o aumento da interatividade, com atribuio um deadline menor e com a priorizao das requisies das operaes READ. Antecipatrio Scheduler O Antecipatrio Scheduler (AS) tenta antecipar futuras operaes de leitura de um processo. Para isso, mantm algumas estatsticas de cada processo e tenta ver se, aps um read, um outro no ocorrer, e espera um certo tempo antes de executar a requisio seguinte na fila.

94

Quando um READ se completa, o escalonador no executa a prxima requisio na fila. Espera 6ms por uma nova requisio do mesmo processo. Se ocorrer, a mesma ser atendida. Para muitas aplicaes, esta espera evita a ocorrncia de inmeras operaes de posicionamento dos cabeotes (seek). Se o processo no executa outra operao READ, este tempo perdido.

Escalonamento no sistema operacional Windows NT/2000/XP Um processo rodando representa uma instncia de uma aplicao, e possui os recursos necessrios sua execuo. Cada processo formado por um conjunto de threads, que a unidade de execuo no sistema operacional Windows. Cada processo possui ao menos uma thread, a thread primria que criada quando o processo carregado para execuo. Para alguns processos, outras threads so criadas, de maneira a explorar o paralelismo da aplicao. A memria alocada para cada processo proporcional a quantidade de threads que o processo possui. Cada thread possui a sua prpria pilha de execuo, seu bcontexto de execuo (representado pelos registradores da CPU) e a sua prioridade. Escalonamento de threads No Windows 2000/XP o escalonador utiliza mltiplas filas de processos aptos a rodar, e os processos interativos (I/O bound) possuem prioridade sobre os CPU bound. O escalonamento de threads no Windows 2000/XP baseado em prioridades. A cada thread nos sistema atribudo um nvel de prioridade, que varia de 0 a 31, sendo que 0 representa o menor e 31 o maior. A prioridade 0 atribuda a uma thread especial do sistema, chamada zero thread, que reponsvel por zerar as pginas livres no sistema. Somente esta thread pode receber a prioridade 0. As prioridades so divididas em duas classes: Real time: prioridades de 16 a 31; 95

Normal: prioridades de 0 a 15.

Existe ainda uma classe especial chamada idle, a de mais baixa prioridade. Threads nesta classe somente executam quando no existirem outras no sistema. Por exemplo, uma thread que faz monitoramento de carga no sistema poderia executar somente quando no existirem outras, de maneira a no interferir na performance. Neste caso, a classe idle deveria ser especificada para esta thread. Para atribuir a CPU a uma thread, o escalonador escolhe a de maior prioridade. Por exemplo, existindo threads de prioridade 31, a primeira da fila ganha o processador. Como trata-se de uma thread da classe real time, executar at terminar ou at esperar por um evento. Ento, existindo outra thread de prioridade 31 esta ser escolhida para ganhar o processador. No existindo, a primeira thread com prioridade 30 ser selecionada. Desta forma, as threads so escolhidas de acordo com a prioridade. Threads com prioridade normal (0 a 15) recebem uma fatia te tempo. Esgotado o tempo, ou quando a thread necessita esperar por um evento, uma outra thread ser selecionada, sempre tero preferncia as threads de maior prioridade. Cada thread ao ser criada recebe uma prioridade base. Para processos com prioridade entre 16 e 31 esta prioridade no se altera. Processos com prioridade entre 0 e 15 possuem sua prioridade ajustada em tempo de execuo. Processos que retornam operaes de I/0 recebem um bnus de aumento de prioridade, que depende do perifrico (ex. 1para disco e 6 para teclado). Aps operaes de sincronizao, recebem tambm um aumento de prioridade, dependendo da natureza do processo (ex. 2 para lider de sesso e 1 para os demais processos). Para processos na classe normal, no sistema Windows 2000 professional, a fatia de tempo de 20 ms (para favorecer a interatividade). Para o Windows 2000 Server, a fatia de tempo de 120 ms. A figura a seguir exemplifica a fila de escalonamento do sistema operacional Windows 2000/XP.

96

Escalonamento em mquinas SMP Durante a instalao do kernel do Windows 2000, a presena de mais de um processador detectada e o suporte ao multiprocessamento carregado. Existe somente uma fila de processos prontos para rodar, e sua estrutura a mesma, com as mesmas classes e nveis de prioridade para uma mquina com um nico processador ou com vrios processadores. No entanto, a existncia de mltiplos processadores permite paralelismo na execuo das threads. O escalonador seleciona a thread de mais alta prioridade para rodar em cada um dos processadores. Alm disso, o Windows 2000 implementa o conceito de afinidade, que define o processador especfico no qual a thread deve executar. A afinidade pode ser hard , que indica a existncia de uma dependncia que obriga a que a thread rode sempre no processador especficado, ou soft, na qual o sistema tenta executar a thread no processador no qual havia sido executada

1T

PX/0002 swodniW on sotpa ed atsil ad oatneserpeR

3T

5T

4T

9T

7T

sedadiroirP eldi 41 51 0 03 61 1 92 laeR opmeT lamroN 13

97

previamente, para aproveitamento de dados da execuo enterior que podem se encontrar em cache, o implicaria em um ganho de performance.
.

Exerccios
1. algoritmo de escalonamento FCFS adequado a um sistema de tempo compartilhado? Porque? 2. Considere um sistema operacional multiprogramado no qual existem trs filas scheduling: 0: de mais alta prioridade na qual rodam os processos do sistema operacional. 1: de prioridade intermediria na qual rodam servidores especializados. 2: de mais baixa prioridade, na qual rodam os programas de usurios. Sabendo que cada uma das filas possui prioridade absoluta sobre as inferiores (isso , somente roda um processo de prioridade 2 se no houver nenhum na fila de prioridade 0 nem na fila de prioridade 1), que na fila de prioridade 0 algoritmo utilizado o FCFS e nas demais o roundrobin: a) Escreva o pseudo-cdigo do procedimento de tratamento da interrupo do relgio. b) Escreva o pseudo-cdigo do procedimento que seleciona um processo para execuo. c) Cite duas situaes em que cada procedimento chamado.

98

3. Alguns sistemas operacionais possuem um conjunto de buffers, cada um com tamanho igual ao de um bloco de disco, e que serve de rea de armazenamento. Supondo que o bloco que contm b no esteja na memria, uma operao de leitura READ (f, &b, nbytes) tratada pelo sistema operacional. da seguinte forma: existe uma lista encadeada de blocos livres, de onde o SO seleciona um bloco para conter o bloco a ser lido do disco; o endereo desse bloco colocado na requisio de IO fabricada pelo SO e encadeada na fila de requisies do perifrico; o SO seleciona um novo processo para execuo; o controlador do perifrico executa a transferncia do bloco que contm o dado indicado na operao de leitura para o bloco alocado previamente pelo SO, no conjunto de buffers; o controlador gera uma interrupo, indicando que terminou a transferncia. Sabendo que: o endereo onde o dado deve ser armazenado e o no. de bytes definido na operao de leitura do usurio tambm fazem parte da requisio fabricada pelo SO; que o sistema possui duas filas de scheduling (0: alta prioridade e 1: baixa prioridade); que o algoritmo de scheduling utilizado nas duas filas o round robin; que os processos que tm seu IO completado possuem sua prioridade aumentada. a) Escreva o pseudocdigo do procedimento que trata a interrupo do perifrico. b) Supondo a existncia de uma nica fila de scheduling, em que os processos no possuem prioridade, reescreva o

99

pseudocdigo do algoritmo de tratamento da interrupo do perifrico. 4. Considerando as caractersticas de um sistema operacional de tempo real hard, composto por trs processos, de mesmo nvel de prioridade, ativados por trs sensores diferentes (cada um associado a um processo), qual(is) o(s) algoritmo(s) de escalonamento mais adequado(s)? Justifique. 5. Considere a seguinte afirmao: em um sistema operacional multiprogramado interativo, diminuindo o tempo de espera nas filas dos processos CPU bound (que necessitam de mais CPU) se diminui o tempo mdio de execuo dos processos . Esta afirmao est correta? Justifique sua resposta apresentando, para quatro processos, a ordem de chegada na ready list, o tempo de execuo, o tempo de espera e o tempo mdio de execuo de cada processo.

Bibliografia

100

5. Sincronizao de Processos
Princpios de Concorrncia. Algoritmos de Excluso Mtua. Princpios de hardware. Instrues Especiais. Semforos. Regio Crtica Condicional. Regio Crtica. Monitores.

5.1 Princpios de Concorrncia


O programa apresentado a seguir, programado em C e com a biblioteca Pthreads, implementa o problema clssico de produtores e consumidores, com buffer circular. No exemplo, um processo produtor gera valores inteiros e os coloca no buffer, de onde o processo consumidor os retira.
#include <pthread.h> #include <stdio.h> #define N 10 pthread_t th0,th1;

int buffer[N], addrprod = 0, addrcons = 0 ;

void * produtor(){ int i, p=50 ;

for(i=0; i<20; i++) { while(((addrprod + 1) % N) == addrcons) {} p++; buffer[addrprod] = p ; addrprod= ( addrprod + 1 ) % N ;

101

} } void * consumidor(){ int i, c ; for (i=0; i<20; i++) { while(addrprod == addrcons) {} c = buffer[addrcons] ; printf(" Consumi o valor %d da posio %d \n",c, addrcons) ; addrcons= ( addrcons + 1 ) % N ; } } int main(){

pthread_create(&th0, NULL, produtor, NULL) ; pthread_create(&th1, NULL, consumidor, NULL) ; pthread_join(th0,NULL); pthread_join(th1,NULL); }

No programa acima, a thread main, aps criar a thread produtor e a thread consumidor se bloqueia, com as primitivas pthread_join, a espera que as threads criadas terminem. Aps a morte das threads produtor e consumidor a thread main termina. Supondo que a primeira thread a ganhar o processador seja a consumidor, ela executa o comando while(addrprod == addrcons) {}. Como a igualdade verificada, o que significa que a posio do buffer na qual a thread produtora deve colocar um dado a mesma que a thread consumidora deve consumir, portanto, o buffer est vazio, esta thread fica em loop no while durante o tempo em que estiver com o processador. Quando a thread produtora ganha o processador, ela executa o comando while(((addrprod + 1) % N) == addrcons) {}. Como o teste falso, a thread deposita na posio addrprod o valor da varivel p e incrementa addrprod.

102

Existindo elementos no buffer, o teste feito pela thread consumidora, no comando while, falso. Portanto, so executadas as instrues seguintes ao while, e aps o loop do comando for. O buffer circular implementado com o uso da operao que utiliza o resto diviso inteira. Por exemplo, se addrcons possui o valor 3, e N possui o valor 10, a prxima posio a ser acessada pelo consumidor Addrcons = (3 + 1) % 10) , ou seja, 4. Se addrcons possui o valor 9, a prxima posio ser ((9 + 1) % 10)), ou seja, a posio 0. Observe que em um buffer de 10 elementos, os ndices variam de 0 a 9. O programa a seguir formado por duas threads , que compartilham uma varivel inteira. O processo to adiciona o valor 5 varivel, e o processo t1 adiciona o valor 2.
#include <pthread.h> #include <stdio.h>

pthread_t tid0,tid1; long a=0, b, c ; void * t0(){ long i ; for (i=0; i<1000000; i++){ a = a + 5 ; } printf("Encerrei a t0 %d\n",sizeof(int)); } void * t1(){ long i ; for (i=0; i<1000000; i++) { a = a + 2; }

103

printf("Encerrei a t1\n"); }

int main(){ pthread_create(&tid0, NULL, t0, NULL) ; pthread_create(&tid1, NULL, t1, NULL) ; pthread_join(tid0,NULL); pthread_join(tid1,NULL); printf("O valor de a e: %d\n",a); }

No programa acima, as threads t0 e t1 compartilham a varivel a. Por exemplo, considerando que aps a compilao deste programa, o cdigo assembler gerado para a thread t0, na operao de atribuio de um novo valor a varivel a seja load a ; // carregar o valor de a no acumulador add 5 ; // adicionar o valor 5 ao acumulador store a ; // armazenar o valor do acumulador na varivel a e para a thread t1 seja load a ; // carregar o valor de a no acumulador add 2 ; // adicionar o valor 2 ao acumulador store a ; // armazenar o valor do acumulador na varivel a Se o valor de a 60, com a seguinte seqncia de operaes, o valor de a ser inconsistente. T0: t0 executa load a e perde o processador: o valor do acumulador (60) salvo. T1: t1 ganha o processador e executa load a: o valor do acumulador 60 T2: t1 executa add 2: o valor do acumulador 62. T3 t1 executa store a: o valor do acumulador armazenado na varivel a (62).

104

T4: t0 ganha o processador, o valor do acumulador restaurado (60) e executa a operao add 5: o valor do acumulador passa a ser 65. T5: t0 executa store a: o valor do acumulador armazenado na varivel a (60). Desta forma, uma atualizao foi perdida, o valor da varivel a, que deveria ser 67, 65.

Seo Crtica de Cdigo um trecho de cdigo no qual os processos executam operaes de modificao em dados compartilhados, e que, portanto, no pode ser executado em paralelo. No exemplo acima, para o processo t0 a seo crtica de cdigo a=a+5; e para o processo t1 a=a+2; Causa do problema: O acesso simultneo varivel por t0 e t1 ocasiona uma inconsistncia na varivel a. Isto significa que o acesso a uma seo crtica de cdigo deve ser feito de forma mutuamente exclusiva.

Definio geral do problema da seo crtica sistema com N processos, N > 1; cada processo executa seu cdigo prprio; os processos compartilham dados variveis, de qualquer tipo; cada processo possui SC s, onde atualizam os dados compartilhados;

105

a execuo de uma SC deve ser de forma mutuamente exclusiva no tempo.

O modelo de soluo para o problema a utilizao de um protocolo de entrada e sada na seo crtica. Assim, para acessar dados compartilhados o processo executa um cdigo de entrada na seo crtica. Ao final, executa um cdigo de liberao da seo crtica, que deve permitir aos outros processos entrarem na sua seo crtica, como exemplificado abaixo. entry-section cdigo-seo-crtica exit-section A entry-section deve garantir que somente 1 processo por vez execute a sua seo crtica e a exit-section permite que outro processo entre na seo crtica.

Requisitos para soluo do problema da seo crtica Para resolver o problema da seo crtica, as seguintes condies necessitam ser obedecidas: a) excluso mtua: somente um processo por vez permitido entrar na seo crtica; b) progresso: deve ser permitido a um processo entrar na sua seo crtica se nenhum outro processo est usando a seo crtica. c) espera limitada: um processo no pode ficar indefinidamente esperando para entrar na seo crtica, enquanto outros processos, repetidamente, entram e saem de suas respectivas sees crticas. Alm disso, deve-se considerar que os processos possuem velocidades indeterminadas; 106

no se deve fazer suposies sobre a velocidade relativa dos processos.

5.3 Algoritmos de Excluso Mtua


A seguir sero apresentados os algoritmos de excluso mtua utilizados para resolver o problema da seo crtica. Solues por SW para 2 processos algoritmo 1 Os processos compartilham uma varivel inteira, TURNO, que indica qual processo pode entrar na seo crtica. Se turno tiver o valor 0, a vez do processo 0, se o valor for 1, deve entrar o processo 1.
var TURNO: integer; % varivel compartilhada; 0 ou 1 EU, OUTRO: integer; % constantes locais, com valores opostos (0,1 e 1,0) repeat while (TURNO !=EU) do {}; % mutexbegin cdigo-da-seo-crtica; TURNO := OUTRO % mutexend resto-do-cdigo; until false;

Este algoritmo no resolve o problema da seo crtica de cdigo, pois requer uma alternncia na execuo. Por exemplo, se o valor inicial de TURNO 0, primeiro deve executar o processo 0, depois o 1, depois o 0, e assim por diante. Isso significa que a condio de progresso no observada. Assim, se o processo 1 executa, passa a vez para o processo 0. Se o processo 0 no deseja ainda entrar na seo crtica, e o processo 1 deseja entrar novamente, o 1 no poder entrar pois a vez do 0. A seguir ser apresentado o algoritmo 1, programado com pthreads

107

#include <pthread.h> pthread_t tid0,tid1;

int turn = 0 ; int shared ; void * p0 (){ int i ; for(i=0; i<10; i++) { while(turn != 0 ) {} //entra se turn = 0 shared =shared + 50 ; printf("Thread1: INCREMENTEI \n"); turn = 1 ; } } void * p1 (){ int i ; for (i=0; i<10; i++) { while(turn != 1 ) {} //entra se turn = 1 printf("Thread2: SHARED: %d \n",shared); turn = 0 ; } } main(){ pthread_create(&tid0, NULL, p0, NULL) ; pthread_create(&tid1, NULL, p1, NULL) ; pthread_join(tid0,NULL); pthread_join(tid1,NULL); }

Solues por SW para 2 processos Algoritmo 2 O problema do primeiro algoritmo a alternncia de execuo, o que no satisfaz a condio de progresso. O processo que est saindo da seo crtica passa a vez para o outro processo, sem saber se o mesmo deseja entrar. No algoritmo a seguir, a varivel TURNO substituda por um vetor do tipo boolean de duas posies, flag. Se flag[i] verdadeiro significa que o processo i est na

108

seo crtica. Um processo somente pode executar a sua seo crtica se o valor de flag correspondente ao outro processo for falso.

// algoritmo 2 var var flag[0..1] of boolean // varivel compartilhada, inicializada com false repeat while flag[j] do {}; % mutexbegin flag[i] := true ; cdigo-da-seo-crtica flag[i] := false % mutexend resto-do-cdigo; until false;

O algoritmo acima no resolve o problema da seo crtica, pois os dois processo podem entrar ao mesmo tempo na seo crtica. Considerando a seguinte seqncia de execuo: To: p0 ganha o processador e encontra o valor de flag[1] false e perde o processador antes de executar a operao flag[i] = true; T1: p1 ganha o processador e encontra o valor de flag[0] false; executar a operao flag[1] = true; e entra na seo crtica. Se p1 perde o processador dentro da seo crtica, p0 ganha o processador e executa a instruo flag[0] = true e vai para a seo crtica. Logo, os dois processos esto na seo crtica, e portanto o algoritmo no implementa excluso mutua.

Algoritmo 2 programado com pthreads:


#include <pthread.h> pthread_t tid0,tid1; int shared = 0 ; int flag [2]; void * p0(){

109

int i ; for(i=0; i<1000000; i++) { while(flag [1] == 1 ) {} /* entra se flag [1] = 0 */ flag[0] = 1 ; shared =shared + 5 ; flag [0] = 0 ; } } void * p1(){ int i ; for (i=0; i<1000000; i++) { while(flag [0] == 1 ) {} /* entra se flag [0] = 0 */ flag [1] = 1 ; shared = shared + 2 ; flag [1] = 0 ; } } main(){ flag [0] = 0 ; flag [1] = 0 ; pthread_create(&tid0, NULL, p0, NULL) ; pthread_create(&tid1, NULL, p1, NULL) ; pthread_join(tid0,NULL); pthread_join(tid1,NULL); printf("O valor final de shared e:%d\n", shared); }

Solues por SW para 2 processos Algoritmo 3 O problema do algoritmo 2 que o processo pode perder o processador antes de mudar o valor da varivel flag, que indica se o mesmo est na seo crtica ou no. No algoritmo a seguir, o processo primeiro modifica o valor de flag para indicar que o mesmo deseja entrar na seo crtica e posteriormente testa a posio que indica que o outro processo est na seo crtica. Se o outro processo no estiver, ele sai do loop e entra na seo crtica

// algoritmo 3 var var flag[0..1] // varivel compartilhada, inicializada com false repeat flag[i] := true ;

110

while flag[j] do skip; // mutexbegin cdigo-da-seo-crtica; flag[i] := false // mutexend resto-do-cdigo; until false;

O algoritmo acima possui as seguintes propriedades: a) satisfaz a excluso mtua, pois somente 1 processo por vez pode entrar na seo crtica; b) no satisfaz a condio de progresso pois se

T0: P0 faz flag[0] = true; e perde o processador T1: P1 faz flag[1] = true; Agora, tanto flag[0] quanto flag[1] possuem o valor verdadeiro. Portanto, P0 e P1 ficam em um loop eterno.

Algoritmo 3 programado com pthreads


#include <pthread.h> pthread_t tid0,tid1; int shared = 0; int flag [2]; void * p0(){ int i ; for(i=0; i<1000000; i++) { flag[0] = 1 ; printf("Thread0%d\n", shared) ; while(flag [1] == 1 ) {} /* entra se flag [1] = 0 */ shared =shared + 5 ; flag [0] = 0 ; } } void * p1(){ int i ;

111

for (i=0; i<1000000; i++) { flag [1] = 1 ; printf("Thread1%d\n", shared) ; while(flag [0] == 1 ) {} /* entra se flag [0] [0] = 0 */ shared = shared + 2 ; flag [1] = 0 ; } } int main(){ flag [0] = 0 ; flag [1] = 0 ; pthread_create(&tid0, NULL, p0, NULL) ; pthread_create(&tid1, NULL, p1, NULL) ; pthread_join(tid0,NULL); pthread_join(tid1,NULL); printf("O valor final de shared e:%d\n", shared); }

Solues por SW para 2 processos O algoritmo a seguir, desenvolvido pelo matemtico T. Dekker em 1962, foi a primeira soluo correta apresentada para o problema da excluso mtua entre dois processos

var flag[0..1] of boolean; false var turn of integer; repeat

// varivel compartilhada, inicializada com

flag[i] := true ; turn := j ; loop exit when not(flag[j]) or turn = i); cdigo-da-seo-crtica flag[i] := false; resto-do-cdigo; until false;

// mutexbegin

// mutexend

O algoritmo satisfaz as propriedades de excluso mtua, progresso e de espera limitada.

112

A excluso mtua seria violada se os dois processos entrassem na seo crtica, que necessitaria que flag[0] e flag[1] tivessem o valor verdadeiro (1). No entanto, como a varivel turn somente pode ter um valor (0 ou 1), favorecendo a um nico processo e garantindo que somente um poderia entrar na seo crtica. A condio de progresso satisfeita porque o processo que deseja entrar encontrar a posio referente ao outro processo, no vetor flag, com o valor 0, indicando que o mesmo no est na seo crtica. Com isso o processo requisitante ir executar a sua seo crtica. A condio de espera limitada somente seria violada se o processo requisitante ficasse bloqueado eternamente no loop, testando a condio de entrada. Isso somente seria possvel se o (a) outro processo tambm estivesse no loop, (b) se o outro processo repetidamente entrasse e sasse da seo crtica e, finalmente, (c) o outro processo no desejasse entrar. O caso (a) impossvel porque a varivel turn sempre favorece um processo. O caso (b) tambm impossvel de ocorrer porque sempre que o processo sai da seo crtica favorece ao outro, setando a varivel turn. No caso (c) a posio no vetor flag correspondente ao outro processo contm o valor 0, portanto o processo requisitante entra na seo crtica.

Solues por SW para 2 processos O algoritmo de Peterson, apresentado em 1981, implementa uma soluo correta para o problema da excluso mtua entre dois processos. Utiliza uma varivel turn, que indica qual processo dever entrar na seo crtica, e um vetor booleano de duas posies, flag, que indica se o processo est na seo crtica. O processo i no entra na seo crtica se flag[j] = true e turn =j. Neste caso, no passa no comando while.

113

var flag[0..1] of boolean; //compartilhada, inicializada com false var turn of integer; repeat flag[i] := true ; turn := j ; while flag[j] and turn = j do nop; // mutexbegin cdigo-da-seo-crtica; flag[i] := false; // mutexend resto-do-cdigo; until false;

O algoritmo de Peterson satisfaz as propriedades de excluso mtua, de progresso e de espera limitada. Excluso mtua: um processo somente entra na seo crtica se o outro no quizer entrar ou se for a sua vez, o que indicado pela varivel turn, o que garante excluso mtua. Progresso: o processo entra na seo crtica se o outro no quizer entrar. Espera limitada: o processo saindo da seo crtica (ex. p0) d a vez para o outro processo (ex. p1), setando a varivel turn, o que garante que p1 somente esperar uma vez que p0 execute a seo crtica, garantindo, portanto, a condio de espera limitada.

Algoritmo de Peterson programado com pthreads.


#include <pthread.h> pthread_t tid0,tid1; int turn ; int shared ; int flag [2]; void * p0(){ int i ; for(i=0; i<10000; i++) { flag[0] = 1 ; turn = 1 ; while(flag [1]==1 && turn==1 ){}/*entra se flag[1]=0 ou turn=0 */ shared =shared + 5 ;

114

flag [0] = 0 ; } } void * p1(){ int i ; for (i=0;i<10000; i++) { flag[1] = 1 ; turn = 0 ; while(flag [0]==1 && turn==0 ){}/*entra se flag[0]=0 ou turn =1*/ shared =shared + 2 ; flag [1] = 0 ; } } int main() { flag [0] = 0 ; flag [1] = 0 ; pthread_create(&tid0, NULL, p0, NULL) ; pthread_create(&tid1, NULL, p1, NULL) ; pthread_join(tid0,NULL); pthread_join(tid1,NULL); printf("O valor final de shared e:%d\n", shared); }

Solues por software para N processos Os algoritmos de Dekker e Peterson, apresentados anteriormente, implementam uma soluo correta para o problema da excluso mtua entre dois processos. Lamport, em 1974, criou o algoritmo da padaria, a seguir apresentado, que soluciona o problema da seo crtica para n processos. No algoritmo de Lamport, para entrar na seo crtica, cada processo precisa obter um ticket e o processo com o ticket de menor valor tem preferncia para entrar na seo crtica. Como a obteno do ticket feita concorrentemente, mais de um processo pode obter o mesmo valor. Neste caso, o nmero do processos usado para escolha. O processo com o menor nmero ter preferncia.

115

// algoritmo da padaria antes de entrar na padaria cliente recebe um nmero; cliente com menor nmero servido; clientes podem receber mesmo nmero, neste caso o identificador dos processos usado para a escolha; nmero menor tem preferncia.

O pseudo-cdigo do algoritmo de Lamport apresentado a seguir. // algoritmo da padaria


// n = nmero de processos // variveis compartilhadas var status: array [0..n-1] of boolean; var ticket: array [0..n-1] of integer; // estrutura do processo Pi //inicialmente status[i] = false; para i = 0 ... i = n-1 ; ticket[i]= 0 ; para i = 0 ... i = n-1 ; Loop { status[i] = true; ticket[i] = 1 + (max(ticket[0], ticket[1], .. , ticket[n-1]); status[i] = false ; for (j=0; j<n-1; j++) { while (status[j]) {} // comando vazio while ( (ticket[j] !=0 && (ticket[j],j < ticket[i], i) {}//Comando vazio } Seo crtica de cdigo ticket [i] = 0 ; // libera seo crtica cdigo no crtico End_loop

O algorimo possui dois vetores, status, no qual o processo sinaliza que deseja tirar um ticket, inicializado com false para todos os processos, e ticket, que contm, para o processo i, 0 quando o mesmo no deseja entrar na seo crtica, ou o valor do ticket, quando o mesmo deseja entrar na seo crtica.

116

No pseudo-cdigo acima, nos primeiros trs comandos aps o Loop, o processo p sinaliza, no vetor status, que deseja entrar na seo crtica (status[i] = true ;) e retira um ticket, que ser o maior valor j obtido pelo seus pares que querem entrar na seo crtica + 1. A seguir, no primeiro comando while, o processo p fica em loop enquanto o processo pj est pegando um ticket. O segundo comando while, garante que o processo p somente entrar ne seo crtica se, para todos os processos j, j no quer entrar na seo crtica ou o ticket do processo p o de menor valor. A liberao da seo crtica feita por ticket [i] = 0, que permitir a entrada de um novo processo. Este algoritmo satisfaz as condies de excluso mtua, de progresso e de espera limitada. Excluso mtua: somente o processo com o menor ticket, ou no caso de dois ou mais processos possurem o mesmo nmero de ticket, o de menor nmero de identificador entra na seo crtica. Progresso: se nenhum outro processo est usando a seo crtica (status [j]=false para todo o j), o processo i entra na seo crtica. Espera limitada: Se todos os demais processos desejarem usar a seo crtica, o processo i pegar o maior valor de ticket, (pior caso), e o processo i espera que n 1 processos executem a seo crtica. Algoritmo de Lamport programado com pthreads, com quatro threads.
#include <pthread.h> #define N 4 #define TRUE 1 #define FALSE 0 pthread_t tid0,tid1, tid2, tid3; int turn ; int shared ; int status [N] , ticket [N], proc_id [N] ; int max_number () { int i, maior ; maior = 0 ; for (i=0; i<N; i++){

117

if (ticket[i] > maior) maior = ticket [i] ; } return (maior + 1) ; } void mutex_begin (int i ) { int j ; status[i] = TRUE; ticket[i] = max_number () ; status[i] = FALSE ; for (j=0; j<n-1; j++) { while (status[j]) {} // comando vazio while ( (ticket[j] !=0 && (ticket[j] < ticket[i]) || (ticket[j] !=0 && (ticket[j] == ticket[i]) && (proc_id[j] < proc_id[i] )) {}//Comando vazio } } void mutex_end (int i ) { ticket [i] = 0 ; } void * p0(){ int my_number = 0 ; int i ; proc_id[my_number] = tid0 ; for(i=0; i<1000000; i++) { mutex_begin (my_number) ; shared =shared + 1 ; mutex_end (my_number) ; } } void * p1(){ int my_number = 1 ; int i ; proc_id[my_number] = tid1 ; for(i=0; i<1000000; i++) { mutex_begin (my_number) ; shared =shared + 1 ; mutex_end (my_number) ; } } void * p2(){ int my_number = 2 ; int i ; proc_id[my_number] = tid2 ; for(i=0; i<1000000; i++) { mutex_begin (my_number) ; shared =shared + 5 ; mutex_end (my_number) ;

118

} } void * p3(){ int my_number = 3 ; int i ; proc_id[my_number] = tid3 ; for(i=0; i<1000000; i++) { mutex_begin (my_number) ; shared =shared + 1 ; mutex_end (my_number) ; } } int main() { int i ; for (i=0; i<N; i++) { status[i] = FALSE ; ticket [i] = 0 ; } pthread_create(&tid0, pthread_create(&tid1, ptrhead_create(&tid2, pthread_create(&tid3, NULL, NULL, NULL, NULL, p0, p1, p2, p3, NULL) NULL) NULL) NULL) ; ; ; ;

pthread_join(tid0,NULL); pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); printf("O valor final de shared e:%d\n", shared); }

5.4 Semforos, Instrues Especiais, Regio Crtica Condicional, Regio Crtica e Monitores
As solues apresentadas contm um grave problema, qual seja o de espera ocupada. Os processos que desejam executar a sua seo crtica necessitam testar a condio de entrada. Se a mesma falsa, toda a sua fatia de tempo do processador ser desperdiada. Em sees crticas grandes, esta demora pode comprometer seriamente o desempenho do sistema.

119

Semforos Uma soluo mais genrica, e que elimina o problema da espera ocupada, so os semforos, desenvolvidos por Dijkstra em 1965. Caractersticas dos semforos:

Um semforo s uma estrutura de dados, formada por um contador e um apontador para uma fila de processos bloqueados no semforo;

Somente pode ser acessado por duas operaes atmicas (P e V); A operao P bloqueia o processo que a executa se o valor do semforo 0;

A operao V incrementa o valor do semforo. Existindo processos bloqueados, o primeiro da fila do semforo acordado;

As modificaes no valor do semforo so executadas atomicamente; Se dois processos tentam, simultaneamente, executar P(s) ou V(s), essas operaes iro ser executadas seqencialmente, em uma ordem arbitrria;

Semforos podem ser usados para excluso mtua com n processos, quando inicializados com o valor 1.

A estrutura de utilizao dos semforos, para cada processo Pi, a seguinte: repeat P(mutex) ; seo crtica V(mutex) seo no crtica 120

until false ; A implementao de semforos feita com o uso de uma estrutura de dados que contm o identificador do semforo, o valor do semforo, um apontador para o primeiro processo bloqueado no semforo e um apontador para o ltimo processo bloqueado no semforo. A operao P no semforo s a seguinte: P(s): s.value = s.value - 1 ; if (s.value < 0 ) { adicionar o processo na lista de processos bloqueados em s block(p) ; /*bloqueia o processo p*/ } Esta operao executada pelo processo que deseja entrar na seo crtica. Se o valor do semforo zero ou menor que zero, o processo fica bloqueado. Caso contrrio, o processo continua a execuo dentro da seo crtica. A operao V(s) executada pelo processo para liberar a seo crtica de cdigo. Se existirem processos bloqueados no semforo, o primeiro da fila liberado. V(s): s.value = s.value + 1 ; if (s.value < =0 ) { remover o processo p da lista s.l wakeup(p) ; /*acorda o processo p*/ }

Semforos Binrios e no binrios (contadores)

121

Um semforo binrio quando somente assume os valores 0 e 1. Se o valor do semforo 0, o processo que executa a operao P fica bloqueado. A operao V verifica a fila do semforo. Se existe algum processo bloqueado, o primeiro acordado, caso contrrio atribudo 1 ao valor do semforo. Um semforo no binrio (semforo contador) pode assumir valores diferentes de 0 e 1. A operao P verifica o valor do semforo. Se o valor do mesmo 0, o valor permanece 0 e o processo fica bloqueado. Sendo maior que 0, decrementado e o processo no fica bloqueado (continua a execuo). A operao V verifica a fila do semforo. Se existe um processo bloqueado, o mesmo acordado. Caso contrrio, o valor do semforo incrementado.

Semforos na biblioteca pthreads A biblioteca pthreads inclui a definio de semforos no binrios e contm primitivas que permitem a inicializao e a utilizao de semforos (operaes para inicializao, P e V). A biblioteca <sys/semaphore.h> contm a definio do tipo semforo sem_t. A declarao de um semforo s realizada da seguinte forma: #include <semaphore.h> sem_t s ; Aps ter sido declarado, a atribuio do valor inicial do semforo feita com a primitiva int sem_init(sem_t *sem, int pshared, unsigned int value); onde, sem: o endereo da varivel semforo; pshared: 0 indica que o semforo no compartilhado com threads em 122

outro processo e diferente de 0 caso contrrio; value: o valor inicial do semforo. Se o valor de retorno da chamada for 0 indica que execuo bem sucedida. Exemplo: #include <semaphore.h> sem_t s; if ( sem_init(&s, 0, 1) != 0 ) { // Erro !!!
}

A operao sem_init inicializa o valor do semforo s com o valor 1, no compartilhado com threads em outros processos. O valor de retorno diferente de zero indica erro na execuo da primitiva. As operaes P e V em um semforo so, respectivamente, sem_wait e sem_post, como mostradas a seguir. int sem_wait(sem_t *s0); int sem_post(sem_t *s0); Exemplo, para o processo Pi, supondo o semforo s definido e inicializado: Pi () { sem_wait(&s); seo crtica sem_post(&s); seo no crtica 123

O exemplo a seguir apresenta um programa escrito em C que utiliza semforos para sincronizar o acesso de duas threads a um buffer de 1 posio. Uma thread (a produtora) deposita valores inteiros no buffer, de onde a thread consumidora os retira e imprime.
#include <pthread.h> #include <semaphore.h> pthread_t tid1,tid2; sem_t s0, s1 ; int buffer; void * produtor(){ int i ; for(i=0; i<100; i++) { sem_wait(&s0) ; buffer = i ; sem_post(&s1) ; } } void * consumidor(){ int i, k ; for(i=0; i<100; i++) { sem_wait(&s1) ; k = buffer ; sem_post(&s0) ; printf("Valor consumido: %d\n", k) ; } } int main(){ sem_init(&s0, 0, 1) ; sem_init(&s1, 0, 0) ; pthread_create(&tid1, NULL, produtor, NULL); pthread_create(&tid2, NULL, consumidor, NULL) pthread_join(tid1,NULL); pthread_join (tid2,NULL); }

124

No programa acima, o semforo s0 inicializado com 1 e o s1 com 0. Se o processo consumidor ganhar o processador, ir ficar bloqueado no semforo s1, e ser desbloqueado aps o produtor ter depositado um elemento no buffer e executar a operao sem_post(&s1). O produtor, por sua vez, ficar bloqueado no semforo s0 at que o consumidor execute a operao sem_post(&s0), o que ocorrer sempre que o consumidor retirar o elemento do buffer.

Problemas clssicos de sincronizao A seguir ser apresentado o problema do buffer limitado, clssico da literatura. Dois processos, um produtor e um consumidor, compartilham um buffer circular de n elementos. Cada elemento tem capacidade de armazenamento de um item de informao. Os semforos usados so: o mutex: para excluso mtua; o empty: contador do nmero de buffers vazios; o full: contador do nmero de buffers cheios. O semforo empty deve ser inicializado com N (nmero de elementos do buffer), full com 0 e mutex com 1. O cdigo do programa apresentado a seguir.

Produtor/Consumidor programado com C e pthreads.


#include <pthread.h> #include <semaphore.h> pthread_t tid1,tid2; sem_t full, empty, mutex ; #define N 10 int buffer[N]; int i=0, j=0 ; // Produtor produz na posio i e consumidor consome da //posio j

125

void * produtor(){

for(;;) { sem_wait(&empty) ; sem_wait(&mutex) ; buffer[i] = 50 ; i = ( i + 1 ) % N ; sem_post(&mutex) ; sem_post(&full) ; } } void * consumidor(){ int j, c ; for (;;) { sem_wait(&full); sem_wait(&mutex); c = buffer[j] ; j = ( j + 1 ) % N ; sem_post(&mutex); sem_post(&empty); } } int main(){ sem_init(&mutex, 0, 1) ; sem_init(&full, 0, 0) ; sem_init(&empty, 0, 10) ; pthread_create(&tid1, NULL, produtor, NULL); pthread_create(&tid2, NULL, consumidor, NULL) pthread_join(tid1,NULL); pthread_join (tid2,NULL); }

Problema do jantar dos filsofos Este problema foi proposto por E. W. Dijkstra em 1965 e refererente a alocaao de recursos entre processos. Consiste de um conjunto finito de processos que compartilham um conjunto finito de recursos, cada um podendo ser usado por um processo de dada vez, podendo ocasionar deadlock ou postergao indefinida. Um grupo de cinco filsofos esto sentados em volta de uma mesa redonda. Existe um garfo entre cada dois filsofos e um filsofo entre cada dois 126

garfos. Cada filsofo tem um prato de espagueti. A vida de um filsofo consiste em pensar e comer e, para isso, precisa de dois garfos. Cada filsofo pode, arbitrariamente, decidir pegar primeiro o garfo da esquerda e depois o da direita, ou vive-versa, mas um garfo somente pode ser usado por um, filsofo de cada vez. Uma soluo trivial a seguinte: // cdigo executado pelos processos filsofos void * filosofo (int fil) { for(;;) { pensar() ; pegar_garfo (fil) ; pegar_garfo (fil + 1) ; comer () ; largar_garfo (fil) ; largar_garfo (fil + 1) ; } } Esta soluo claramente leva a deadlock. Imaginando-se que cada processo pegue o seu garfo da esquerda, todos ficariam bloqueados a espera do garfo da direita. Uma soluo simples poderia ser usar um semforo binrio, inicializado com o valor 1. Aps a chamada pensar() seria colocada a operao P e aps a chamada largar_garfo (fil + 1) ca operao V. No entanto, esta soluo no satisfatria, pois permite que somente um filsofo por vez coma. Existem inmeras solues para o problema: a) os garfos so numerados e cada filsofo tenta pegar o garfo adjacente de nmero maior primeiro; b) os filsofos so coloridos, vermelho e azul. Os vermelhos tentam pegar o garfo da esquerda primeiro, os azuis tentam pegar o garfo da direita primeiro; c) existe um monitor central que controla a atribuio de garfos aos filsofos;

127

d) existe uma caixa com n tickets (n o nmero de filsofos). Cada filsofo precisa obter o ticket antes de pegar os garfos; A seguir sero apresentadas duas solues para este problema, baseadas nas solues apresentadas por E. W. Dijkstra [Dijkstra, E. W., 1971] e no cdigo escrito por A. S. Tanembaun [A. S. Tanembaun 2000]. Na primeira soluo, os filsofos sero classificados em dois grupos (vermelho/azul). Os filsofos vermelhos primeiro tentam pegar o garfo da esquerda, os azuis, o garfo da direita. Esta soluo, embora correta, no simtrica, isto , os filsofos no executam o mesmo cdigo. usado um vetor de semforos, cada um representando um garfo, inicializados com o valor 1, indicando que o garfo est disponvel. A segunda soluo que ser apresentada baseada na soluo de Dikcorreta e permite o mximo de paralelismo para um nmero qualquer de filsofos. Ela utiliza um vetor para manter o estado corrente dos processos (com fome, comendo, pensando) e um vetor de semforos no qual, um filsofo com fome tentando adquirir um garfo poderia ficar bloqueado se o garfo estivesse em uso. Nesta soluo, um filsofo somente pode passar para o estado comendo se os seus vizinhos no estiverem comendo.
//Soluo para o problema do jantar dos filsofos na qual os filsofos // so classificados em vermelhos e azuis #include <pthread.h> #include <semaphore.h> # # # # define define define define N PENSANDO COM_FOME COMENDO 5 0 1 2

pthread_t tid[N]; sem_t garfos[N]; void pensar ( int fil) { int t ; t = rand()%N ; printf("O filosofo %d vai pensar %d segundos\n", fil, t) ; sleep (t) ; }

128

void comer (int fil) { printf("Vai comer o filosofo %d\n", fil) ; sleep (2) ; }

void pegar_garfos(int fil){ if ( fil % 2 == 0 ) { //Vermelhos: pegar o garfo da sem_wait(&garfos[fil]) ; sem_wait(&garfos[(fil+1) % } else { // Azuis: pegar o garfo da sem_wait(&garfos[(fil+1) % sem_wait(&garfos[fil]) ; } } void depositar_garfos(int fil){ sem_post(&garfos[fil]) ; sem_post(&garfos[(fil+1) % N] ); } void * filosofos (void * fil) { int i ; for (i=0;i<10; i++) { pensar((int)fil) ; pegar_garfos((int)fil) ; comer((int)fil) ; depositar_garfos((int)fil) ; } } int main(){ int i ;

esquerda e aps o da direita N] );

direita e aps o da esquerda N] );

for (i=0; i<N;i++) sem_init ( &garfos[i], 0, 1); for (i=0; i<N;i++){ pthread_create(&tid[i], NULL, filosofos, (void *)i); } for (i=0; i<N;i++){ pthread_join(tid[i],NULL); }

129

// Problema do jantar dos filsofos que //um nmero qualquer de filsofos #include <pthread.h> #include <semaphore.h> # # # # define define define define N PENSANDO COM_FOME COMENDO 5 0 1 2

permite paralelismo para

pthread_t tid[N]; sem_t s[N], mutex ; int estado [N] ; void pensar ( int fil) { int t ; t = rand()%N ; printf("O filosofo %d vai pensar %d segundos\n", fil, t) ; sleep (t) ; } void comer (int fil) { printf("Vai comer o filosofo %d\n", fil) ; sleep (2) ; } void teste (int fil) { if(estado[fil]==COM_FOME && estado[(fil+N-1)%N]!=COMENDO && estado[(fil+1)%N] != COMENDO) { estado[fil] = COMENDO; printf("O filosofo %d esta comendo\n", fil) ; sem_post(&s[fil]) ; } } void pegar_garfos(int fil){ int i ; sem_wait(&mutex) ; estado[fil] = COM_FOME ; teste(fil) ; sem_post(&mutex) ; sem_wait(&s[fil]) ; } void depositar_garfos(int fil){ int i ; sem_wait(&mutex) ; estado[fil] = PENSANDO ;

130

teste((fil+N-1)%N) ; teste(fil+1%N) ; sem_post(&mutex) ; } void * filosofos (void * fil){ int i ; for (;;) { pensar((int)fil) ; pegar_garfos((int)fil) ; comer((int)fil) ; depositar_garfos((int)fil) ; } }

int main(){ int i ; for(i=0; i<5; i++) { sem_init (&s[i], 0, 0); estado[i] = PENSANDO ; } sem_init ( &mutex, 0, 1); for (i=0; i<=N;i++){ pthread_create(&tid[i], NULL, filosofos, (void *)i); } for (i=0; i<N;i++) { pthread_join(tid[i],NULL); } }

Problema do barbeiro dorminhoco Tambm proposto por W. E. Dijkstra, este um outro problema clssico de comunicao entre processos. Em uma barbearia trabalha apenas um barbeiro e existe um nmero limitado de cadeiras para os clientes esperarem, se o barbeiro estiver ocupado cortando o cabelo de um cliente. Caso no existam clientes, o barbeiro dorme at que seja acordado pelo prximo cliente e comece a cortar o cabelo. Se chega um cliente enquanto o barbeiro estiver ocupado le deve sentar-se em uma das cadeiras livres (se houver) e aguardar at que o barbeiro termine seu trabalho e chame o prximo cliente. Se no houverem cadeiras livres o cliente vai embora. O problema consiste em sincronizar a ao do barbeiros e dos clientes.

131

#include <pthread.h> #include <semaphore.h> pthread_t tid1,tid2; sem_t cliente, barbeiro, mutex ; #define cadeiras 10 int esperando = 0 ; void * clientes(void * cli){ sem_wait(&mutex) ; if (esperando <= cadeiras){ esperando = esperando + 1 ; sem_post(&cliente) ; sem_post(&mutex) ; sem_wait(&barbeiro) ; printf("Cliente %d cortando o cabelo\n", cli) ; sleep (4) ; //corta o cabelo } else sem_post(&mutex) ; } void * barbeiros(){ int j ; for(j=0; j<10; j++) { sem_wait(&cliente); sem_wait(&mutex) ; esperando = esperando - 1 ; sem_post(&barbeiro) ; sem_post(&mutex); printf("Barbeiro cortando o cabelo de um cliente\n") ; sleep (4) ; } } int main(){ int i ; sem_init(&mutex, 0, 1) ; sem_init(&cliente, 0, 0) ; sem_init(&barbeiro, 0, 0) ; for (i=0; i<10;i++) pthread_create(&tid1, NULL, clientes, (void *)i); pthread_create(&tid1, NULL, barbeiros, NULL) ; for (i=0; i<11;i++) { pthread_join(tid1,NULL); } }

Problema dos leitores e escritores

132

Este problema, proposto por Courtois e outros em 1971, utilizado para modelar o acesso concorrente de processos leitores e escritores a uma base de dados. O acesso pode ser feito por vrios leitores simultaneamente. Se um escritor estiver executando uma alterao, nenhum outro leitor ou escritor poder acessar a base de dados. Duas solues, desenvolvidas por Courtois e implementadas com Pthreads, sero apresentadas a seguir. A primeira prioriza os leitores. Os escritores devem acessar a base de dados de forma mutuamente exclusiva, mas se houver um leitor acessando os dados, outros leitores que o desejarem podero faz-lo. A segunda soluo prioriza os escritores. Da mesma forma que na primeira soluo, os escritores devem acessar a base de dados de forma exclusiva e os leitores podem compartilhar o acesso. Porm, se um escritor desejar executar uma operao, dever faz-lo o mais rapidamentre possvel. Em outras palavras, um leitor no dever acessar a base de dados se houver um escritor esperando. Primeira soluo prioridade para os leitores: nesta soluo, o semforo r usado pelos leitores para atualizar de forma mutuamente exclusiva a varivel countleitor, que conta o nmero de leitores querendo acessar a regio crtica. O semfor mutex usado para excluso mtua no acesso aos dados compartilhados por leitores e escritores. O semforo mutex usado somente pelo primeiro leitor ao entrar na seo crtica e pelo ltimo leitor, ao sair.
#include <pthread.h> #include <semaphore.h> #define N 10 pthread_t tid1[N], tid2[N] ; sem_t r, mutex ; int countleitor=0; void * leitor(void * i){ sem_wait(&r) ; countleitor = countleitor + 1 ; if (countleitor == 1) sem_wait(&mutex) ; sem_post(&r) ; //acessa os dados

133

sleep (2) ; printf("Sou o leitor %d\n", i) ; sem_wait(&r) ; countleitor = countleitor - 1; if (countleitor == 0) sem_post(&mutex) ; sem_post(&r) ; } void * escritor(void * i){ sem_wait(&mutex); //atualiza os dados sleep (2) ; printf("Sou o escritor %d\n", i) ; sem_post(&mutex); } int main(){

int i ; sem_init(&mutex, 0, 1) ; sem_init(&r, 0, 1) ; for (i=0; i<N;i++) { pthread_create(&tid2[i], NULL, escritor, (void *)i) ; pthread_create(&tid1[i], NULL, leitor, (void *)i); } for (i=0; i<N;i++) { pthread_join(tid1[i],NULL); } for (i=0; i<N;i++) { pthread_join(tid2[i],NULL); } }

A segunda soluo para o problema dos leitores e escritores, apresentada a seguir, prioriza os escritores. Os semforos r e w so usados para proteger o acesso aos dados compartilhados. O primeiro escritor que passar pelo semforo r ir bloquear os leitores que no podero manipular mutex1 e w. mutex3 garante acesso exclusivo aos leitores ao bloco de cdigo de sem_wait(&r) at sem_post(&r).

#include <pthread.h> #include <semaphore.h>

134

pthread_t tid1[10], tid2[10]; sem_t r, w, mutex1, mutex2, mutex3 ; #define N 10 int nleitores = 0, nescritores = 0; void * leitor(void * i){ sem_wait(&mutex3) ; sem_wait(&r) ; sem_wait(&mutex1) ; nleitores = nleitores + 1 ; if (nleitores == 1) sem_wait(&w) ; sem_post(&mutex1) ; sem_post(&r) ; sem_post(&mutex3) ; //acessa os dados sleep (1) ; printf("Sou o leitor %d\n", i) ; sem_wait(&mutex1) ; nleitores = nleitores - 1 ; if (nleitores == 0) sem_post(&w) ; sem_post(&mutex1) ; } void * escritor(void * i){ sem_wait(&mutex2) ; nescritores = nescritores + 1 ; if (nescritores == 1) sem_wait(&r) ; sem_post(&mutex2) ; sem_wait(&w) ; //modifica os dados sleep (1) ; printf("Sou o escritor %d\n", i) ; sem_post(&w) ; sem_wait(&mutex2) ; nescritores = nescritores - 1 ; if (nescritores == 0) sem_post(&r) ; sem_post(&mutex2) ;

} int main(){

int i ; sem_init(&mutex1, 0, 1) ; sem_init(&mutex2, 0, 1) ; sem_init(&mutex3, 0, 1) ; sem_init(&w, 0, 1) ;

135

sem_init(&r, 0, 1) ; for (i=0; i<N;i++) { pthread_create(&tid1[i], NULL, leitor, (void *)i); pthread_create(&tid2[i], NULL, escritor, (void *)i) ; } for (i=0; i<N;i++) { pthread_join(tid1[i],NULL); } for (i=0; i<N;i++) { pthread_join(tid2[i],NULL); } }

Solues de Hardware para o problema da seo crtica Em alguns processadores existem instrues especiais que permitem a implementao de solues para o problema da excluso mtua. Duas destas instrues so Test and Set e Swap.

TAS: Test And Set - Testa e modifica o contedo de uma varivel de forma no interrompvel Swap: Troca o contedo de duas variveis de forma no interrompvel

A execuo de uma instruo TAS, retorna o valor de uma varivel global, inicializada com o valor false, e atribui verdadeiro varivel. Desta forma, se o valor verdadeiro, retorna verdadeiro e atribudo o valor verdadeiro. Se o valor falso, retorna falso e atribudo o valor verdadeiro. O pseudo-cdigo a seguir representa a execuo da instruo TAS. int lock = 0; // global int tas (){ r = lock ; lock = 1 ; return (r) ; 136

} A instruo swap troca o contedo de duas variveis. Uma varivel global inicializada com o valor falso. Cada processo define uma varivel local, inicializada com o valor verdadeiro, cujo contedo ser trocado com a varivel global. Assim, se o valor da varivel global verdadeiro, retorna na varivel local o valor verdadeiro e varivel global atribudo, na troca, o valor verdadeiro. Se a varivel global possui o valor falso, retorna falso na varivel local ao processo e varivel global atribudo o valor verdadeiro. O pseudo-cdigo a seguir representa a execuo de uma instruo swap. int lock = 0; % global inicializada com false swap (lock, key){ int r ; r = lock ; lock = key ; key = r ; } Uma possvel forma de oferecer o uso dessas instrues com dois procedimentos, enter_region e exit_region. A seguir sero apresentados estes procedimentos, programados com uma pseudo-linguagem de montagem. A implementao com TAS a seguinte: int lock = 0; /* varivel global enter_region (){ L: tas register, #lock /* o valor de lock atribudo a register e a lock

137

atribudo o valor 1 operao atmica */ cmp register, #0 /* compara com 0 */

jne L /* se no for 0 a SC est ocupada, loop */ ret } leave_region (){ move lock, #0 /* atribui 0 a varivel lock - libera a SC */ ret } A estrutura dos processos que participam da seo crtica pi() { for(;;) { enter_region() ; seo crtica leave_region() ; seo no crtica } } Para entrar na seo crtica o processo chama o procedimento enter_region(). Se a seo crtica estiver ocupada, o valor da varivel lock verdadeiro e o processo ficar em loop, dentro do procedimento. No caso do valor ser falso, o processo termina o procedimento enter_region() e executa a seo crtica. Ao

138

terminar a seo critica o processo a libera chamando o procedimento leave_region(), que atribui o valor falso a varivel lock. Com a instruo SWAP os procedimentos so int lock = 0; % global inicializada com false indicando que a SC est livre enter_region(int key) { L: swap #lock, #key /* troca o contedo de lock e key atomicamente */ cmp #key, 0 /* compara o contedo de key com 0 */

jne L /* se for 1 a SC est ocupada, loop */ rte } Neste procedimento, o valor das variveis lock e key so trocados atomicamente. Se o valor de lock verdadeiro (seo crtica ocupada), o processo fica em loop at que se torne falso (seo crtica livre). O procedimento leave_region(): leave_region() { move #lock, 0 /* libera a SC */ rte } libera a seo crtica, atribuindo o valor 0 varivel lock. O primeiro processo que ganhar o processador e executar o procedimento enter_region() ganhar acesso a seo crtica. A estrutura dos processo que utilizam a seo crtica pi() {

139

for(;;) { int key = 1 ; enter_region(key) ; seo crtica leave_region() ; seo no crtica } } de maneira anloga a soluo com a instruo TAS, Cada processo para entrar na seo crtica executa o procedimento enter_region(key). Se o valor de lock for verdadeiro, a SC est ocupada e o processo ficar em loop. Quando lock se torna falso, a seo crtica est livre e o processo continua a execuo. O procedimento exit_region() libera a seo crtica, atribuindo o valor falso varivel lock.

Regies Crticas Condicionais e Regies Crticas Estes mecanismos representam solues de mais alto nvel para o problema da excluso mtua, sendo mais natural de serem incorporados em uma linguagem de programao. Considerando-se o uso de semforos, muito fcil provocar erros em sua utilizao. Por exemplo: - pode-se omitir uma operao P; - pode-se omitir uma operao V; - pode-se, no lugar de uma operao P, colocar V e vice-versa;

140

- pode-se utilizar a seo crtica sem colocar operaes P e V. - etc.

Regies Crticas Condicionais (Hoare 1972; Brinch Hansen 1972 e 1973) Regio crtica condicional um mecanismo que garante excluso mtua no acesso aos dados compartilhados. A excluso mtua garantida porque somente permitido a um processo por vez executar as instrues dentro de uma regio crtica condicional. A forma do comando a seguinte: region V when b do S; b: expresso booleana avaliada quando o processo entra na regio crtica. Se b verdadeira, a lista de comandos S executada seno o processo libera a excluso mtua e suspenso at que a expresso booleana se torne verdadeira. O programa apresentado a seguir ilustra o uso deste mecanismo.

)* selbairav derahs eht *( ;tnuoc ,tuo ,ni ,fub : bb ECR UOSER ;0 =: ]N..1[ : tnuoc ,tuo ,ni ;meti FO ]N..1[ YARRA : fub RAV ;01 = N TSNOC ;recudorp DNE ;DNE ;DNE ;1 + tnuoc =: tnuoc ;N dom ) 1 + ni( =: ni ;i =: ]ni[fub OD N < tnuoc NEHW bb NOIGER ;)i(ecudorp POOL NIGEB ;meti : i RAV ;recudorp SSECORP
141

O trecho de cdigo acima contm por dois processos, um produtor e outro consumidor, que utilizam regio crtica condicional como mecanismo de excluso mtua. O processo produtor produz elementos no buffer se existe uma posio disponvel. Caso contrrio o mesmo ficar bloqueado, no comando region, at que a condio seja verdadeira (count < n), isto , existam posies disponveis no buffer. O processo consumidor retira elementos do buffer. Se o buffer est vazio (count = 0), o processo consumidor fica bloqueado no comando region at que a condio se torne verdadeira. Um inconveniente da regio crtica condicional que os processos necessitam reavaliar continuamente a expresso lgica. Alm disso, a avaliao da condio feita antes do processo entrar na regio crtica. Muitas vezes, a avaliao da condio deve ser feita dentro da seo crtica, o que na soluo de Brinch Hansen, apresentada a seguir (regio crtica mais operaes await e cause), possvel de ser feito.

Regies Crticas ( Brinch Hansen 72 ) Com este mecanismo, uma varivel compartilhada, v, do tipo T definida como

;remusnoc DNE ;DNE ;)i(remusnoc ;DNE ;1 - tnuoc =: tnuoc ;N DOM )1 + tuo( =: tuo ;]tuo[fub =: i OD 0 > tnuoc NEHW bb NOIGER POOL NIGEB ;meti : i RAV ;remusnoc SSECORP
142

Var v: shared T ; Processos concorrentes somente podem acessar a varivel compartilhada dentro de um comando estruturado chamado critical region. region v do S ; esta notao associa a execuo do comando S a regio crtica v. A varivel compartilhada v somente pode ser acessada dentro de um comando region. Se Processos concorrentes acessam simultaneamente o comando region, o primeiro passa e ir executar o comando S. Os demais ficam bloqueados na entrada da regio crtica. Isso significa que o comando region garante excluso mtua no acesso aos dados definidos como compartilhados. Processos cooperantes necessitam, em inmeras situaes, esperar por certas condies. Por exemplo, um processo consumidor necessita esperar que um processo produtor produza os dados que o mesmo ir consumir. A operao await (e) [Brinch Hansen 1972] libera a regio crtica e bloqueia o processo a espera de uma condio. Segundo Brinch Hansen, o processo fica bloqueado em uma fila de eventos. A primitiva cause(e) acorda todos os processos bloqueados na fila de eventos e. O pseudo-cdigo apresentado a seguir ilustra o uso destas primitivas. // consumidor region v do //produtor region v do 143

begin while not B do await (e) ; S1 ; end ;

begin S2 ; cause (e) ; end () ;

No programa acima, o processo consumidor fica bloqueado, pela execuo do comando await(e), se a expresso B falsa. Ser acordado pela operao cause(e), que sinaliza que a expresso B se torna verdadeira para o processo consumidor, que poder recomear a execuo. Embora a biblioteca Ptrhreads no implemente regio crtica, tal como definido por Brinch Hansen, possvel utilizar os comandos pthread_mutex_lock() e pthread_mutex_unlock() para obter-se excluso mtua no acesso a dados compartilhados. As variveis mutex devem ser globais e uma chamada pthread_mutex_lock que tenha obtido a seo crtica faz com que outras threads que esto tentando adquirir a seo crtica fiquem bloqueadas, at que a thread que detm a regio crtica a libere via pthread_mutex_unlock. Mutex podem ser usados para sincronizar threads no mesmo processo ou em processos diferentes. Para ser possvel a utilizao de mutex por threads de processos diferentes, as variveis mutex devem ser alocadas em uma memria compartilhada pelos processos. A primitiva

int pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr); inicializa a varivel mutex mp com os atributos especificados por attr. Se attr NULL, os atributos padro so utilizados. Aps a inicializao, o estado do mutex inicializado e unlocked. Com os atributos padro, somente threads no mesmo processo podem operar com a varivel mutex. A primitiva int pthread_mutex_lock(pthread_mutex_t *mp);

144

fecha o mutex referenciado por mp. Se o mutex j est fechado, o processo que efetua esta chamada primitiva int pthread_mutex_unlock(pthread_mutex_t *mp); chamada pela thread proprietria do mutex mp para liber-lo. Se existem threads bloqueadas, o escalonador chamado para escolher a thread que ir obter o mutex. Se a thread que executa a chamada no a proprietria do mutex, um erro retornado e o comportamento do programa indefinido. fica bloqueado at que o mutex seja liberado. Se a thread proprietria do mutex executa esta chamada, ocasionar um deadlock. A

O programa a seguir, que ilustra o uso destes comandos, faz a gerencia de alocao de blocos de disco. O processo que deseja alocar um bloco, chama o procedimento acquire, que retorna um nmero de bloco. Se o nmero retornado for superior a 1023, no existia um bloco disponvel. Na funo principal deste programa so criadas 5 threads, que executam o cdigo thr, e inicializada a varivel barrier_lock, do tipo mutex.

//Exemplo de Regio Crtica programada com pthreads


#include <pthread.h> pthread_t tid; pthread_mutex_t barrier_lock; int disk [1024] ; int acquire () { int i ; pthread_mutex_lock(&barrier_lock);\ i = 0 ; while(i < 1024 && disk[i] == 1) i++ ; if (i < 1024) disk[i] = 1 ; pthread_mutex_unlock(&barrier_lock); return(i) ; } void thr(int i){

145

int j, k ; printf(" EU SOU A THREAD : %d\n",i); for (j=0; j<10; j++){ k = acquire () ; if(k < 1024) printf("THREAD: %d OBTIVE O BLOCO %d \n",i, k); sleep(1); } } int main(){ int i; for(i=0;i<1024;i++) disk[i] = 0 ; pthread_mutex_init(&barrier_lock,NULL); for (i=0;i<5;i++) pthread_create(&tid, NULL, thr, NULL); for (i=0;i<N;i++) pthread_join(tid, NULL); printf("FIM DO MAIN\n"); }

biblioteca

Pthreads

possui

as

operaes

pthread_cond_wait()

pthread_cond_signal(), definidas como segue: int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); Os parmetros so a varivel condio cond e o mutex. A primitiva int pthread_cond_signal(pthread_cond_t *cond) possui como parmetro a varivel condio cond.

pthread_cond_wait propriedades: so usadas

pthread_cond_signal

apresentam

as

seguintes

dentro

do

comando

pthread_mutex_lock(&mutex)

pthread_mutex_unlock(&mutex);

146

so

associadas

uma

regio

crtica,

usadas

nos

comandos

pthread_mutex_lock/pthread_mutex_unlock; a operao pthread_cond_wait(&mutex, &cond) bloqueia o processo que a executa na varivel condio cond e libera a regio crtica mutex ; a operao pthread_cond_signal(&cond) acorda um processo bloqueado na varivel condio cond; a operao pthread_cond_signal no produz efeito se no houver processos bloqueados na varivel condio cond.

O programa a seguir ilustra o uso destas primitivas.


#include <pthread.h> pthread_cond_t cond0 ; pthread_cond_t cond1 ; pthread_t tid0; pthread_t tid1; pthread_mutex_t mutex; int buffer ; void * produtor(){ int j, k ; for (j=0; j<100; j++){ pthread_mutex_lock(&mutex) ; while (x == 1) pthread_cond_wait(&cond1, &mutex) ; buffer = j * 5 ; X = 1 ; pthread_cond_signal(&cond0) ; pthread_mutex_unlock(&mutex) ; } } void * consumidor(){ int j, k ; for (j=0; j<100; j++){ pthread_mutex_lock(&mutex) ; while (x == 0) pthread_cond_wait(&cond0, &mutex) ; printf (Valor do buffer: %d\n, buffer) ; X = 0 ; pthread_cond_signal(&cond1) ; pthread_mutex_unlock(&mutex) ; } }

147

int main(){ pthread_mutex_init(&mutex,NULL); pthread_create(&tid0, NULL, produtor, NULL); pthread_create(&tid1, NULL, consumidor, NULL); pthread_join(tid0, NULL); pthread_join(tid1, NULL); }

No programa acima, se o valor da varivel x for igual a zero, o processo consumidor fica bloqueado, na operao pthread_cond_wait(&cond0), at que seja sinalizado pelo processo produtor, o que ocorre aps o mesmo ter atribudo um valor varivel buffer e o valor 1 varivel x, pela execuo da operao pthread_cond_signal(&cond). De maneira anloga, o processo produtor fica bloqueado na operao processo consumidor, pthread_cond_wait(&cond1) at ser sinalizado pelo o que ocorre pela operao

pthread_cond_signal(&cond1). Observe que so utilizadas duas variveis condio, uma pelo processo produtor e outra pelo processo consumidor.

Monitor [ Brinch Hansen 73, Hoare 74] Um monitor um tipo abstrato de dados que contm os dados que representam o estado de um determinado objeto, os procedimentos que manipulam este objeto, e um cdigo de inicializao que assinala o estado inicial do objeto. Os procedimentos de um monitor so comuns a todos os processos que acessam o monitor. Porm, a execuo destes procedimentos feita de forma mutuamente exclusiva. Se dois processos chamam ao mesmo tempo um mesmo procedimento, o primeiro a fazer a chamada executar, enquanto que o segundo ficar a espera que o procedimento termine e que o monitor seja liberado e que a sua chamada seja executada. Variveis especiais ( condio ) permitem a um processo se bloquear a espera de uma condio (wait). A condio sinalizada por um outro processo (operao signal). A figura a seguir apresenta a viso de um monitor.

148

Dados Globais P0 P1 P2

Cdigo de Inicializao

Viso Esquemtica de um Monitor A figura acima apresenta um monitor formado por trs procedimentos, o cdigo de inicializao, que executado quando o monitor comea a rodar, e os dados globais. Contm tambm uma fila, formada pelos processos P0, P1 e P2, que esto bloqueados a espera da liberao do monitor para executar um procedimento (Proc0, Proc1 ou Proc2) do monitor. Variveis condio so associadas ao conceito de monitor, e so utilizadas para bloquear/desbloquear processos que esto a espera de recursos. Por exemplo, pode-se definir as variveis x e y, do tipo condio com a notao var x, y : condition ; A operao x.wait () ; bloqueia o processo que a executa na varivel condio x. A operao x.signal () ;

3corP
149

2corP

1corP

acorda um processo bloqueado na varivel condio x. S no existem processos bloqueados, a operao no produz efeitos. Considerando estas operaes, um problema que pode surgir o seguinte: Se a operao x.signal executada por um processo P0 e existe um processo P1 bloqueado, P0 e P1 podem executar. Se P1 acordado, P0 e P1 ficam ativos simultaneamente no monitor, o que viola o principio da excluso mtua. Possibilidades de soluo: a) P0 acorda P1 e se bloqueia, liberando o monitor P0 recomea a execuo quando P1 liberar o monitor; P0 recomea a execuo quando P1 se bloquear a espera de outra condio. b) P0 sinaliza a condio de P1 e no libera o monitor P1 espera que P0 libere o monitor; P1 espera que P0 se bloqueie a espera de condio, o que libera o monitor.

A soluo adotada por Brinch Hansen, na linguagem Pascal Concorrente [Brinch Hansen 1977] resolve o problema de uma forma simples, a operao signal deve sempre ser o ltimo comando dentro de um procedimento do monitor. Assim, P0 executa signal e libera o monitor ( o signal a ltima instruo da procedure ). A seguir ser apresentado um programa Pascal Concorrente que exemplifica o uso de monitor. Pascal Concorrente uma extenso da linguagem Pascal, na qual Brinch Hansen acrescentou trs tipos abstratos de dados: processos, classes e monitores, identificados pelas palavras chaves process, class, monitor. O

150

programa a seguir formado por um monitor e por dois processos. O monitor usado para controlar o acesso exclusivo a um recurso e possui dois procedimentos: request e release. O processo que chama request bloqueado, pela operao delay ( x ), se o recurso est ocupado. Para liberao do recurso o processo que o detm chama o procedimento release, que assinala que o recurso livre e executa a operao continue (x), que acorda um processo bloqueado na varivel condio x, se existir. No existindo processo a ser acordado, o sinal gerado pela operao continue perdido, isto , no memorizado. Os procedimentos que so visveis pelos processos so os que contm a palavra reservada entry. No exemplo, no existem procedimentos locais ao monitor (sem a palavra reservada entry). O monitor possui um cdigo de inicializao, (begin/end do monitor) que executado quando o monitor declarado (instanciado). No main do programa (trecho begin/end.), so declaradas as variveis do tipo process e monitor, definidos anteriormente. Os processos recebem o monitor como parmetro, na operao init, que os coloca em execuo.

//Programa Pascal Concorrente


type resource = monitor var free : boolean ; x : queue ;

procedure entry request ; begin if not free them delay ( x ) ; free : = false ; end procedure entry release ; begin

151

free : = true ; continue ( x ) ; end begin free : = true; end. Type user = process ( r = resource ); begin r.request ; r.release ; end; Type user1 = process ( r = resource ); begin r.request ; r.release ; end; begin var p0 : user ; p1 : user1 ; m : resource ; init po ( m ) ; init p1 ( m ) ; end;

O cdigo a seguir apresenta a implementao de um semforo binrio com monitor.


type semaphore = monitor ; var busy = boolean ; nom_busy : queue ;

.dne .amargorp o ritucsiDA

152

procedure entry P begin if busy then delay (nom_busy) ; busy = free ; end; Procedure entry V begin busy = false ; continue (nom_busy); end ; begin busy = false ; end.

A seguir ser apresentada a implementao de um semforo no binrio com monitor.


type semaphore = monitor ; var nproc = int ; non_busy : queue ; procedure entry P () begin nproc--; if nproc<0 then delay (non_busy) ; end; Procedure entry V () begin nproc++; continue (non_busy) ; end ; begin nproc = n;d. end;

153

rotinom// .dne

rotinom od // nigeb } ;)c(eunitnoc )* rotudorp o azilanis *( ;1 + tnuoc =: tnuoc ;XAM dom )1 + tuo( = tuo ; ]tuo[reffub = I )* reffub on otnemele ovon mu acoloc *( o i z a v t s e r e f f u b o , r i z u d o r p a r e p s e / / ; )p yaled )0 = tnuoc( fi { )regetni :i rav( ariter yrtne erudecorp
(

} ;)p(eunitnoc )* rodimusnoc o azilanis *( ;1 + tnuoc =: tnuoc ;XAM dom )1 + ni( =: ni ;i =: ]ni[reffub )* reffub on otnemele ovon mu acoloc *( oiehc tse reffub o ,rimusnoc arepse// ; )c yaled )XAM = tnuoc( fi { )regetni :i( atisoped yrtne erudecorp
(

; eueuq : c ,p ;regetni : tuo ,ni ,tnuoc ;regetni fo ]XAM..0[ YARRA : reffub rav ; 01 = XAM tsnoc ; rotinom = reffub_dednuob epyt
buffer limitado.

Exerccios
O monitor apresentado a seguir implementa uma soluo para o problema do Problema do buffer limitado

154

1. Considere a existncia de um semforo para controlar a passagem de automveis em um cruzamento, que no existe prioridade de uma rua em relao outra, que o trnsito nos dois sentidos nas duas ruas e que deve passar, alternadamente, um automvel de cada rua, em cada um dos sentidos. Desenvolva uma soluo para este problema. Modele os carros como threads e utilize semforos para sincronizao. 2. Considere a existncia de uma ponte em um desfiladeiro, com capacidade para passar somente uma pessoa de cada vez. Viajantes da regio da Floresta Alta possuem prioridade em relao aos viajantes da regio do Grande Rio. Somente aps cinco viajantes da Floresta Alta terem atravessado a ponte que um viajante da regio do Grande Rio pode atravessar em sentido contrrio. Desenvolva uma soluo para este problema. Modele os viajantes como threads e utilize semforos para sincronizao. 3. Escreva um programa formado por dois processos concorrentes (threads), leitor e impressor, que executam um loop infinito, e que sincronizam suas aes com o uso de semforos. O processo leitor fica lendo caracteres do teclado e colocando em um buffer de 132 posies. Quando o buffer est cheio o processo impressor deve imprimi-lo. 4. Escreva um monitor, com dois procedimentos, deposita e imprime. O processo leitor chama o procedimento deposita, para inserir caracteres no buffer (132 posies). O processo impressor chama o procedimento imprime, para imprimir o buffer, quando o mesmo estiver cheio. 5. Escreva um programa formado por dois processos concorrentes, leitor e impressor, que executam um loop infinito, e que sincronizam suas aes com o uso da soluo de Peterson, para o problema da excluso mtua. O processo leitor l caracteres do teclado e os coloca em uma lista encadeada, cujos nodos so alocados dinamicamente. O processo impressor fica continuamente retirando os caracteres da lista e imprimindo.

155

6. Considerando que dois processos, um produtor e um consumidor compartilham um buffer de um elemento, escreva um programa concorrente com o uso da soluo de Peterson para sincronizar as aes do produtor e do consumidor. 7. Escreva um programa concorrente formado por trs threads, uma consumidora (c) e duas produtoras (p0 e p1), que executam um loop eterno. A thread consumidora recebe informae (um valor inteiro) da thread p0 no bufer b0 e da thread p1 no buffer b1 (primeiro consome de b0 e depois consome de b1). Os buffers b0 e b1 possuem capacidade de armazenar um nico elemento. A thread consumidora somente pode consumir se existirem informaes no buffer e as threads produtoras somente podem voltar a produzir depois da thread consumidora haver retirado as informaes do buffer. Utilize semforos para a excluso mtua no acesso aos buffers. 8. Escreva um programa concorrente formado por dois processos (THREADS) que sincronizam suas aes com o uso de semforos. Um dos processos conta at 500, e ento deve esperar pelo outro que conta at 1000, e viceversa. Considere que a execuo comea pela THREAD que conta at 500. 9. Com o uso de semforos construa uma implementao dos procedimentos enqueue e dequeue, que controlam o uso de recursos de forma mutuamente exclusiva, definidos como segue: enq(r): if inuse (r){ insere p na fila de r ; block(p) ; } else inuse = true ; deq(r): p = primeiro da fila de r ; if p != null ativar p ; else inuse (r) == false ; 10. Regio crtica implementada em Pthreads com os comandos: pthread_mutex_t lock; /* define lock como uma varivel do tipo mutex */

156

pthread_mutex_lock(&lock); seo crtica*/

/* Previne mltiplas threads de executar a

pthread_mutex_unlock(&lock); /* Libera a seo crtica*/ pthread_cond_t c ; /* define uma varivel condio c */ pthread_cond_wait (&lock, c) ; /* bloqueia o processo na varivel condio c, associada a regio crtica lock*/ pthread_cond_t signal ( c ) ; /* acorda um processo bloqueado na varivel condio c */ Escreva os procedimentos alocaBuffer ( ) e liberaBuffer ( ), que acessam um vetor compartilhadode 100 posies, e que mantm um mapa de ocupao de buffers de memria. As posies disponveis so marcadas com 0 e ocupadas com o valor 1. 11) Escreva um monitor que implementa um buffer de 132 elementos e composto por duas procedures, getBuf e putBuf. O procedimento putBuf recebe como parmetro um valor que deve ser armazenado no buffer. O procedimentpo getBuf cheio e buffer vazio. 12) Regio crtica implementada em Pthreads com os comandos: mutex_t lock; /* define uma varivel lock do tipo mutex */ mutex_lock(&lock); seo crtica*/ mutex_unlock(&lock); /* Libera a seo crtica*/ que uma thread criada com a primitiva /* Previne mltiplas threads de executar a retorna um elemento do buffer. Considere a necessidade de sincronizao nas situaes de buffer

Supondo

pthread_create(nomefunc) e que a funo pthread_ join () bloqueia a thread que a executa at que uma thread filha termine, escreva um

157

programa formado por duas threads, uma produtora e uma consumidora que compartilham um buffer de um nico elemento. A soluo poderia ser melhorada com o uso de alguma(s) primitiva(s)? Qual(is)?

Bibliografia

158

6. Comunicao entre Processos por Troca de Mensagens


Comunicao entre Processos: Memria Compartilhada. Troca de Mensagens. Primitivas de Comunicao. Comunicao em Grupo. Chamada Remota de Procedimento. Estudo sobre MPI: Message Passing Interface.

6.1 Comunicao entre Processos


Processos cooperantes, componentes de uma aplicao, em inmeras situaes necessitam trocar informaes. Com memria compartilhada, os processo compartilham variveis e trocam informaes atravs do uso de variveis compartilhadas. Sem memria compartilhada, os processos compartilham informaes atravs de troca de mensagens ( passing messages). Neste modelo, o S.O responsvel pelo mecanismo de comunicao entre os processos. A comunicao de Processos por Troca de Mensagens permite a troca de informaes entre processos que no compartilham memria. As duas primitivas bsicas so send e receive. send: utilizada por um processo para enviar uma msg. Pode ser bloqueante ou no bloqueante.

159

receive: utilizada por um processo para receber uma msg. Essa operao bloqueante, o processo que a executa fica bloqueado at o recebimento de uma mensagem.

A sincronizao entre processos nos sistemas que implementam troca de mensagens, implcita s operaes. A operao send pode ser bloqueante ou no bloqueante, e a operao receive, normalmente, bloqueante. Desta forma, um processo que executa uma operao receive permanece bloqueado at o recebimento de uma mensagem, enviada com uma operao send. Uma outra operao existente reply, usada por um processo para responder a uma mensagem recebida. Pode conter uma informao de resposta ou simplesmente pode indicar que uma mensagem enviada com uma operao send foi recebida sem erros. A operao reply no bloqueante. A comunicao por troca de mensagens pode ser direta ou indireta. Na comunicao direta simtrica os processos se identificam mutuamente, isto , o remetente identifica o recebedor e o recebedor identifica o remetente. Ex.:

/ * processo 0 * / main ( ) { send (t1, &m); }

// processo 1 main ( ) { receive (t0, &m); }

Na comunicao direta assimtrica o remetente identifica o recebedor e o recebedor recebe de qualquer remetente, o que indicado por -1 no campo que identifica o remetente, na operao receive.

160

// processo 0 main ( ) { send (t1, &m); }

// processo 1 main ( ) { receive (-1, &m); }

Quando a comunicao indireta, existe uma entidade intermediria atravs da qual os processos se comunicam, denominada porta ou mailbox. Exs.: sistema operacional MACH, sockets. O direito de receber mensagens enviadas sobre uma porta pode ser do processo criador ou de todos os processos que possuem o direito de acesso porta. As operaes sobre portas so: p = port-create ( ); Esta operao utilizada para criar uma porta de comunicao. Ao trmino da operao, p contm a identificao da porta criada. port-destroy (p); Esta operao elimina uma porta. Ao trmino da operao, a porta p deixa de existir. Mensagens associadas a porta p no recebidas sero perdidas. send (p, m); Permite a um processo enviar uma mensagem m para uma porta p. As mensagens sero colocadas em uma fila de mensagens ainda no consumidas, associadas porta p. receive (p, m); Utilizada por um processo para receber uma mensagem. Ao trmino da operao, m conter a primeira mensagem da fila de mensagens associada porta p. Se no existirem mensagens na porta p, o processo ficar bloqueado,

na fila de processos bloqueados a espera de mensagens. O pseudo-cdigo a seguir ilustra o uso destas primitivas.

port_t p; // processo 0 p0 ( ) { while(1){ send (p, &m); } }

// processo 1 p1 ( ) { while(1){ receive (p, &m); } } main() { p=port_create(); create (p0); create (p1) ; } No sistema operacional desenvolvido para o computador RC400[The Nucleus of a Multiprogramming System, Brinch Hansen 1970], Brinch Hansen utilizou troca de mensagens para implementar a comunicao entre processos.

162

O sistema possui um ncleo, com as funes mais bsicas de salvamento e restaurao de contexto, tratamento de interrupes, escalonamento, as funes de criao e gerenciamento de processos que podem ser chamadas por outros processos e as funes de comunicao entre processos. As demais funcionalidades do sistema foram implementadas como processos concorrentes. O sistema possui dois tipos de processos: internos e externos. Processos internos so os programas em execuo e processos externos so relacionados s operaes de entrada e sada. O ncleo do sistema gerncia um conjunto de buffers de mensagens do sistema e uma fila de mensagens para cada processo. A comunicao entre os processos internos no sistema pode ser feita com o uso das seguintes primitivas: send message (receiver, message, buffer): copia a mensagem message para o primeiro buffer disponvel dentro do pool de buffers e coloca na fila do receptor receiver. O receptor ativado se estiver esperando uma mensagem. O remetente continua aps receber a identificao do buffer da mensagem. wait message (sender, message, buffer): o processo fica bloqueado at que uma mensagem seja depositada em sua fila. Quando isso acontece, o processo acordado e est de posse do nome do processo remetente (sender), do contedo da mensagem (message), e da identidade do buffer de mensagem. O buffer removido da fila e tornado disponvel para transmitir uma resposta. send answer (result, answer, buffer): copia a resposta answer no buffer utilizado pela mensagem recebida e o coloca na fila do processo que enviou a mensagem. O sender da mensagem ativado se est esperando por uma resposta. O processo que executa a operao send answer continua imediatamente aps a execuo da primitiva. wait answer (result, answer, buffer): bloqueia o processo que a executa at que

163

uma resposta chegue no buffer especificado. Quando a resposta chega copiada para o espao de endereamento do processo (answer ) e o buffer retornado para o pool de buffers do sistema. result especifica se a resposta foi enviada por um outro processo ou pelo ncleo do sistema, se a mensagem foi enviada a um processo no existente.

6.2 Comunicao em Grupo


Comunicao em Grupo um modelo de comunicao que envolve um grupo de processos. Neste modelo, vrias formas de comunicao so possveis, podendo-se destacar a comunicao um-para-todos, todos-para-um e todospara-todos. Na comunicao um-para-todos, tambm chamada de difuso, um dos processos membros do grupo envia dados para o restante do grupo. Na comunicao todos-para-um os processos pertencentes a um mesmo grupo enviam uma mensagem para um nico processo destinatrio. Na comunicao todos-para-todos, cada membro de um grupo envia uma mensagem para os demais componentes do grupo. Da mesma forma que na troca de mensagens ponto-a-ponto, a difuso de mensagens para um grupo e a recepo de mensagens produzidas por membros de um grupo podem ser bloqueantes ou no-bloqueantes. Entre as principais vantagens do modelo de comunicao em grupo podese citar a maior facilidade de expresso da comunicao envolvendo mltiplos processos, assim como o melhor desempenho que este tipo de comunicao pode oferecer em comparao troca de mensagens ponto-a-ponto (a que envolve um processo emissor e um processo receptor). A primeira vantagem pode ser evidenciada supondo-se que uma mensagem deva ser enviada para mltiplos processos e que no existam primitivas de comunicao em grupo, o processo emissor, ter que enviar uma mensagem para cada processo receptor. Assim, o processo remetente dever enviar tantas mensagens quantos forem

164

os processos destinatrios. No entanto, se os processos destino forem includos em um grupo, basta para o emissor enviar uma nica mensagem (de difuso) este grupo para que todos os processos a recebam. A segunda vantagem da comunicao em grupo, diz respeito ao maior desempenho que pode ser oferecido por este tipo de comunicao, comparado ao da troca de mensagens ponto-a-ponto. Como a comunicao em grupo um mecanismo de mais alto nvel, os detalhes de sua implementao so totalmente transparentes ao usurio, o que permite que protocolos mais eficientes possam ser utilizados para a implementao da comunicao. Considerando ainda o exemplo da difuso de uma mensagem, a implementao deste tipo de interao entre processos pode levar em conta o nodo onde os mesmos residem, de forma que apenas uma mensagem seja endereada a cada nodo contendo processos que devam receber a mensagem. Deste modo, quando a mensagem chega em um nodo destino ser encaminhada a todos os processos que devem receber a mensagem no nodo. Na comunicao em grupo, vrios aspectos, especialmente relacionados organizao interna dos grupos, devem ser levados em considerao. Conforme sua organizao interna, grupos podem ser classificados em estticos ou dinmicos, abertos ou fechados, pares ou hierrquicos Um grupo esttico se, aps ter sido formado, permanece sempre com o mesmo conjunto de membros. O tamanho, isto , o nmero de elementos deste tipo de grupo constante. Em um grupo dinmico, processos podem entrar e sair do grupo sempre que necessrio. O tamanho deste tipo de grupo portanto varivel. Grupos fechados no permitem que processos de fora se comuniquem com o grupo. Somente a comunicao entre os membros do grupo permitida. Nos grupos abertos possvel que processos de fora do grupo se comuniquem com seus membros. Um grupo par quando no existe hierarquia entre os seus membros, isto , todos os processos que pertencem ao grupo so iguais. Existindo hierrquia o grupo classificado como hierrquico. Neste caso, um processo o coordenador e os demais so os trabalhadores. o coordenador

165

quem recebe as mensagens endereadas ao grupo e escolhe o trabalhador que dever executar a ao. As figuras a seguir apresentam dois grupos, um aberto no hierrquico e um fechado hierrquico.

P4 mensagem P0 P1 P5 Grupo aberto no hierrquico

P6

P3 P2

P4 P0 P1 P5 P3 P2

Grupo hierrquico fechado No caso do grupo aberto no hierrquico, a mensagem enviada pelo processo P6, no pertencente ao grupo, ser recebida por todos os membros do grupo. No grupo fechado hierrquico, o coordenador do grupo, P0, encaminha uma mensagem a todos os demais participantes do grupo.

166

6.3 Remote Procedure call


O modelo cliente/servidor corresponde a idia de estruturar um sistema operacional em um grupo de processos cooperantes, os servidores que fornecem servios a outros processos, os clientes. Esse modelo foi usado em vrios sistemas (Amoeba[Mu90], Chorus[Ar89], Mach[Ac86], Windows NT, etc.) e em sistemas operacionais para mquinas paralelas (ex. Helios[Ba90]). Nesse modelo, um cliente envia uma mensagem a um servidor solicitando um servio e fica bloqueado esperando a resposta: a chamada de procedimento a distncia (RPC). O modelo RPC As chamadas de procedimentos `a distncia (RPC) so um eficiente mecanismo de comunicao usados nos sistemas distribudos e nos sistemas para mquinas paralelas sem memria comum, organizados de acordo com o modelo cliente/servidor. O modelo RPC [Bi84] uma extenso distribuda do modelo procedural existente nas linguagens de programao tradicionais. A idia principal permitir a chamada de um procedimento em uma mquina por um programa sendo executado em outra mquina. Em um RPC, um programa em uma mquina P, (o cliente) chama um procedimento em uma mquina Q, (o servidor) enviando os parmetros adequados. O cliente suspenso e a execuo do procedimento comea. Os resultados so enviados da mquina Q para a mquina P e o cliente acordado. Nos sistemas distribudos o uso de RPC permite obter um

comportamento idntico a uma chamada de procedimento nos sistemas operacionais tradicionais. Por exemplo, nos sistemas operacionais tradicionais as chamadas de sistema so implementadas por procedimentos que so

167

chamados pelos programas dos usurios. Essas procedures recebem recursos especficos da arquitetura fsica (ex. Trap).

os

parmetros (ex. nos registradores da mquina) e so invocadas com o uso de

No caso de um RPC, o funcionamento de uma chamada no assim to simples. O esquema de funcionamento proposto por Nelson[Bi84] o seguinte: Toda funo que pode ser chamada distncia definida no lado do cliente por uma procedure chamada stub client. Essa procedure recebe os parmetros e os coloca em uma mensagem, adicionando a identificao da procedure chamada e transmite essa mensagem ao processo/processador servidor. O servidor, quando recebe a mensagem, procede a extrao dos parmetros e chama a procedure especificada na mensagem. No fim da execuo da procedure, realizada a operao inversa: Colocao dos resultados e envio da mensagem de resposta ao processo cliente. A procedure que realiza essa operao chamada de stub server. Finalmente, a procedure stub client recebe os resultados, termina e retorna o controle ao cliente .

168

Uma qualidade importante deste esquema que ele repousa unicamente no modelo de processos comunicantes. Por isso, ele funciona independentemente da localizao do cliente e do servidor. Se eles so localizados na mesma mquina a comunicao se far localmente, seno ela se far atravs da rede. O funcionamento desse modelo coloca em jogo cinco elementos: O processo cliente; O processo servidor; O procedimento chamado distncia; O procedimento stub client ; O procedimento stub server.

Os modelos sncrono e assncrono Em um RPC sncrono o cliente suspenso at o momento que a resposta chegue. Uma crtica a esse modelo que ele no explora o paralelismo existente entre cliente e servidor nas arquiteturas paralelas ou distribudas. Em um RPC assncrono, a chamada no suspende o cliente e as respostas so recebidas quando elas so necessria. Assim, o cliente continua a sua execuo em paralelo com o servidor. Independentemente do assincronsmo entre cliente e servidor, existe tambm o paralelismo possvel na execuo de uma procedure. Essa execuo pode ser exclusiva e as chamadas serialisadas. Em um outro extremo podese permitir tantas execues concorrentes quantas forem as chamadas em um dado momento. Por exemplo, para cada chamada de procedimento recebida por um servidor ele pode criar uma thread para tratla e voltar a aceitar novas requisies. Uma nova requisio que chega pode ser de um procedimento j em execuo por uma thread, o que no impedir a criao de uma nova thread para executar uma nova instncia desse procedimento. 169

O princpio da soluo Um RPC sncrono trata as chamadas locais e distantes de maneira idntica. O princpio da soluo adotada o seguinte: o cliente faz a chamada uma procedure de biblioteca (stub client). Essa procedure pega os parmetros, junta a identificao da procedure e do servidor que deve tratar a chamada, coloca essas informaes em uma mensagem e a envia. O cliente suspenso. A localizao do servidor destinatrio da mensagem pode ser feita pelo sistema operacional, com um servidor de nomes, ou o usurio pode especificar o servidor ao qual a mensagem dirigida. O servidor pode ser local ou distante. As etapas de uma chamada local so as seguintes: 1. O cliente chama a procedure e envia os parmetros 2. O cliente suspenso 3. A procedure constri a mensagem 4. Envia a mensagem para o ncleo local de comunicao 5. O ncleo de comunicao analisa o header da mensagem e descobre que o servidor local (mesmo processador) 6. Aloca um buffer 7. Faz uma cpia da mensagem para o buffer 8. Coloca o endereo do buffer na fila de mensagens do servidor 9. Acorda o servidor 10. O servidor pega a mensagem 11. Analisa os parmetros

170

12. Dispara a procedure correspondente ao servio 13. Fabrica a mensagem de resposta 14. Envia a mensagem de resposta ao ncleo de comunicao 15. O ncleo de comunicao acorda o cliente 16. O stub client extrai os resultados 17. O cliente que fez a chamada inicial recomea A figura a seguir mostra uma chamada um servidor local.

Troca de mensagens entre cliente e servidor local

No que diz respeito as chamadas de servidores distantes, a diferena a ao do ncleo de comunicao: 1. Procura em sua tabela de servidores a identificao do servidor 2. Envia a mensagem endereada a este servidor 3. O ncleo de comunicao do processador destinatrio recebe a mensagem 4. Analisa seu header e determina o servidor destinatrio

171

5. Aloca um buffer e copia a mensagem 6. Coloca o endereo do buffer na fila de mensagens do servidor e o acorda A figura abaixo apresenta uma troca de mensagens entre cliente e servidor distantes.

Troca de mensagens entre cliente e servidor distantes Implementao Nesta seo ser feita uma breve descrio de uma detalhada a implementao de um RPC sncrono. A mquina Supernode A mquina Supernode pertence a categoria MIMD, sem memria comum, formada por processadores Transputer. Sua configurao bsica pode ter de 16 32 processadores de trabalho e um processador que desenvolve funes especiais, denominado de controlador. Ela possui ainda, como elementos principais, um comutador de ligaes uma via de controle. O comutador de ligaes um Cross bar 72x72 e a via de controle permite a comunicao entre o transputer de controle e os de trabalho. mquina paralela,

denominada Supernode e do ncleo local a cada processador. Aps ser

172

Com o uso do Cross bar, o controlador, que responsvel pela realizao das conexes f'sicas entre os processadores, pode conectar dois links fsicos de dois transputers quaisquer permitindo assim a configurao de diferentes topologias (ex. anel, etc.). O ncleo local O ncleo que roda em cada nodo processador possui trs nveis lgicos: O ncleo de comunicao, o ncleo local e o nvel dos usurios (figura a seguir).

O ncleo de comunicao responsvel pela recepo e encaminhamento de mensagens locais ou entre processadores. No caso de recepo de uma mensagem, duas situaes podem se produzir: na primeira, a mensagem lhe pertence e ele deve transmitla ao processo destino; na segunda, a mensagem pertence a um outro processador e ele deve encaminhla propriamente para que ela chegue ao seu destino. Este encaminhamento progressivo assegurado em cada nodo por uma funo de routagem local, definida por uma tabela de roteamento. Esta tabela tambm utilizada para o envio de mensagens distantes. Quando uma mensagem gerada localmente, o ncleo de comunicao ativado. Se o processador destino um outro, ele envia a mensagem pelo caminho apropriado, em caso contrrio, ele a envia ao processo local. O nvel chamado de ncleo local responsvel pelas funes de gerncia de processos e de gerncia de memria. Ele implementa operaes de: 173

Criao/destruio de processos; Sincronizao entre processos; Alocao/liberao de memria.

No nvel usurios que executam todos os servidores do sistema. tambm neste nvel que rodam as aplicaes dos usurios. Descrio do RPC implementado A implementao do modelo RPC caracterizada pela estrutura e troca de mensagens, pelo stub client, pelo servidor, pelo stub server e pelo mecanismo de troca de mensagens. A mensagem A mensagem (figura a seguir) pode ser dividida em duas partes: Um header e um corpo. O header possui a identificao tipo da mensagem, do cliente e do servidor e o corpo contm a mensagem propriamente dita. O tipo pode ser um SEND (pedido de servio) ou um REPLY (resultados da execuo de uma funo). O cliente identificado por (processador, &message). Processador onde ele reside e &message contm o semforo no qual ele est bloqueado a espera da resposta. O servidor identificado por (Processador, Servi dor, Numero_funo). Processador o processador onde o servidor reside. Servidor identifica o servidor. A cada servidor existente no sistema associado um nmero inteiro, conhecido globalmente. Numero_funo identifica a funo que o servidor dever executar. Da mesma maneira que um servidor identificado por um nmero inteiro, as funes tambm o so. Por exemplo, se ao servidor FILE-SYSTEM associado o nmero 1 e a procedure READ o nmero 7, considerandose que esse servidor resida no processador 1, a chamada: n = read (file_descriptor, &buffer, nbytes);

174

far com que seja construda uma mensagem endereada ao processador nmero 1, servidor nmero 1 que dever executar a procedure de nmero 7. O corpo da mensagem pode ser formado por palavras, registros, ou ambos e constituem os parmetros de chamada da funo. Em qualquer caso, especificado na mensagem o nmero de palavras e o nmero de registros que ela contm. A figura a seguir mostra a organizao de uma mensagem.

Estrutura de uma mensagem O stub client Quando um cliente faz um RPC, ele chama uma procedure de biblioteca, stub client, com os parmetros apropriados. Essa procedure fabrica a mensagem e a envia ao ncleo local de comunicao que a envia ao servidor local ou ao processador destinatrio, se o servidor distante. O cliente fica bloqueado esperando a resposta. O servidor A funo de um servidor de tratar demandas de clientes. Cada servidor responsvel por um conjunto de servios, por exemplo, o File System responsvel pelas funes de gerncia de arquivos, o Memory manager pelas funes de gerncia de memria, etc. Os servidores executam o seguinte procedimento: Pegar a primeira mensagem da fila; Identificar a funo; Verificar o nmero de parmetros;

175

Chamar a procedure correspondente.

176

A procedure se executa Chamar o stub server para fabricar a resposta Ativar o ncleo para retransmitir a resposta

A estrutura geral de um servidor ( ex. file system ) a seguinte: main() { for(;;) { P(message); switch (message.fonction) -case READ: do_read() ; case WRITE: do_write() ; } } O stub server A funo do stub server construir a mensagem de resposta. Para isso, ele pega os resultados e os coloca em uma mensagem. Os resultados podem ser palavras ou registros e, em qualquer caso, a respectiva quantidade deve ser especificada na mensagem. Aps, ele inverte o header da mensagem, isso , ele pega processador origem e o coloca como destinatrio e destinatrio como origem. Como identificao de processo destinatrio ele coloca o semforo no qual o cliente est bloqueado a espera da resposta. O ncleo de comunicao 177

do processador origem da mensagem (ping por ex.), quando receber essa mensagem a identificar como resposta e, nesse caso, desbloquear o processo cliente (operao V no semforo). O mecanismo de troca de mensagens O mecanismo de base que suporta a troca de mensagens no sistema o ncleo de comunicao. Esse ncleo organizado em torno de threads. Existem dois tipos de threads: Um que recebe as mensagens do canal fsico e que permite a comunicao entre processadores diferentes. Como o processador do Supernode o Transputer que possui quatro canais fsicos de comunicao, existe uma thread associada a cada canal. O outro tipo formado por threads de controle que so associadas aos processos existentes no sistema, existindo uma para cada processo. Esse ltimo grupo encarregado de enviar as mensagens, locais ou distantes, que so geradas pelo processo. Esse ncleo o suporte bsico para os protocolos de comunicao que so implementados no sistema: Cliente/servidor, biponto( bloqueante e no bloqueante ) e difuso. Um exemplo de RPC Para mostrar mais em detalhes a execuo de um RPC, ser apresentada uma chamada simples ping, que permite saber se um processador est ativo. Considere um cliente que executa no processador 5 o comando i = ping ( 12 ) ; onde i um inteiro e 12 o processador que se quer saber se est ativo. A procedure

int ping ( int proc ) { -message m ; 178

m.origem.client = &m ; m.dest.proc = 12 ; m.dest.serveur = SYSTEM ; m.dest.fonction = PING ; m.message_type = SEND ; out ( channel , &m ) ; P ( m.semaforo ) ; } fabrica a mensagem. Ela aloca uma estrutura mensagem (m), a qual ela completa com os parmetros recebidos e com outras informaes. Em m.origem.client ela coloca o endereo da mensagem, depois ela completa os campos que identificam o processador, o servidor e o tipo da mensagem (SEND). Ento, ela ativa o ncleo de comunicao com a operao out . Cada processo no sistema possui uma thread de controle que lhe associada quando de sua criao e que pertence ao ncleo de comunicao. A comunicao entre o processo e a sua thread de controle feita atravs de um canal lgico global a essas duas entidades. A thread fica sempre a espera de uma mensagem nesse canal ( operao in) e ela ativada pela operao out nesse canal. A instruo out ( channel ,&m ) coloca no canal lgico o endereo da mensagem e ativa a thread. Assim, a mensagem enviada do processo para o ncleo de comunicao. A seguir, o cliente bloqueado, com a operao P no semforo que existe na mensagem. A thread que ativada executa

in ( channel, m ) ;

179

m.origem.proc = my-number ; /* 5 neste exemplo */ canal_fisico = get_route( m>dest.proc ) ; out ( canal-fisico, m ) ; A operao in recebe a mensagem. A thread completa a mensagem com a identificao do processador origem, nmero lgico atribudo a cada processador quando da fase de boot e conhecido do ncleo. Aps, com o uso da funo get-route obtm o canal fsico a partir do qual o processador destino (12) acessvel e envia a mensagem por esse canal com a operao out(canal_fisico, m ). A mensagem atravessa a rede de processadores e chega no ncleo de comunicao do processador 12. A thread do ncleo de comunicao que recebe as mensagens que chegam pelo canal a partir do qual o processador 5 a enderea executa:

buffer = in ( canal_fisico, m ) ; switch ( buffer.dest.serveur ) -case SYSTEM: -coloca a mensagem na fila do servidor V( descripteur_serveur[SYSTEM].semaforo ) ; break ; case MEMORY_MANAGER: case FILE_SYSTEM: --

180

Inicialmente a thread l a mensagem do canal fsico e a coloca em um buffer. Cada servidor no sistema descrito por um registro descritor que contm, entre outras informaes, o endereo de uma fila de mensagens a ele endereadas e um semforo no qual ele fica bloqueado a espera de uma mensagem. A entrada descripteur_serveur[SYSTEM] no array de descritores descreve o servidor SYSTEM. A thread coloca a mensagem na fila do servidor SYSTEM e o acorda com a operao V em seu semforo. O cdigo do servidor o seguinte: system () { -for (;;) { P( descripteur_serveur[SYSTEM].semaforo ) ; message = descripteur_serveur[SYSTEM].m ; switch (message.fonction ) -case PING: message.type = REPLY ; message.msg_reply = 1 ; message.dest.proc = message.m.origem.proc ; message.dest.serveur = &message ; out ( channel, &message ) ; break ; } 181

} Quando o servidor SYSTEM recomea, pela ao da operao V, ele pega a mensagem, simbolizado pela instruo message = descripteur_serveur[SYSTEM].m) e identifica a funo. No caso de um PING a funo muito simples, consiste unicamente em enviar a resposta. Ento, ele fabrica a mensagem colocando REPLY como tipo, 1 no campo msg_reply indicando sucesso na execuo do PING e inverte os campos que identificam o processador na mensagem original. Assim, o processador origem se torna destinatrio e o destinatrio origem. Como servidor destinatrio ele coloca o endereo da mensagem e a envia ao ncleo de comunicao com a operao out que desbloqueia a sua thread de controle. A thread de controle completa a mensagem colocando a identificao do processador como origem e analisa o processador destinatrio. Neste caso um outro ( 5 ), ele obtm o canal fsico a partir do qual esse processador acessvel canalfisico = get_route( m>dest.proc ) e envia a mensagem. A seguir apresentado o fragmento de cdigo da thread que corresponde a essas aes. in ( channel, message ) ; message.origem.proc = my_number ; /* 12 neste exemplo */ if ( message.dest.proc ! = my_number ) { canal_fisico = get_route( message>dest.proc ) ; out ( canal_fisico, message ) ; } else

182

para uma mensagem local O ncleo de comunicao do processador originrio da mensagem ( 5 ) recebe a mensagem e a reconhece como resposta. Neste caso, ele acorda o cliente com a operao V no semforo que ele estava bloqueado. O cdigo a seguir apresenta a recepo da resposta. in ( link-fsico, m ) ; if ( m.type == REPLY ) V ( m.semaforo ) ; else um pedido de servio par um servidor

6.4 Estudo de caso: Message Passing Interface - MPI


MPI uma biblioteca de comunicao que permite a programao paralela baseada em troca de mensagens. Foi definida pelo MPI Frum (www.mnpiforum.org), com a participao de Universidades, empresas, laboratrios de pesquisa. A verso 1.0, definida no MPI Frum, se tornou disponvel em maio de 1994, e contm as especificaes tcnicas da interface de programao. Em MPI uma execuo compreende um ou mais processos que se comunicam chamando rotinas da biblioteca para enviar e receber mensagens. Este conjunto de rotinas pode ser utilizado a partir de programas escritos em ANSIC ou Fortran Um programa MPI formado por um conjunto fixo de processos, criados no momento da inicializao, sendo que criado um processo por processador. Cada um desses processos pode executar um programa diferente, o que caracteriza o modelo de programao MPMD. No entanto, uma forma natural de programar utilizando o modelo SPMD, no qual um mesmo programa

183

disparado em cada um dos processadores participantes da execuo e em cada processador selecionado para execuo um trecho do programa. O padro MPI define funes para: Comunicao ponto a ponto; Operaes coletivas; Grupos de processos; Contextos de comunicao; Ligao para programas ANSI C e Fortran 77; Topologia de processos. A verso 1.1 de MPI possui um enorme conjunto de funes (129). No entanto, com um nmero reduzido (apenas 6) possvel resolver uma grande variedade de problemas. Neste documento sero apresentadas as funes bsicas de comunicao ponto a ponto que, juntamente com mais um numero reduzido de funes permite o desenvolvimento de programas. Sero tambm apresentados exemplos de programas escritos em MPI e as principais caractersticas de MPI-2, verso definida em 1997 que incorpora novas caractersticas de programao paralela biblioteca MPI.

Conceitos bsicos
A seguir sero apresentados alguns conceitos bsicos MPI. Processo Cada programa em execuo se constitui um processo. Desta forma, o nmero de processadores especificado pelo usurio quando dispara a execuo do programa indica o nmero de processos (programas) em execuo. Se o nmero de processadores fsicos menor que o nmero especificado, os

184

processos so criados, circularmente, de acordo com a lista de processadores especificada na configurao do ambiente. Mensagem o contedo de uma comunicao, formada por duas partes:

Identificao dos processos (transmissor e receptor); Rtulo da mensagem; Comunicator.

Endereo onde o dado se localiza; Nmero de elementos do dado na mensagem; Tipo do dado. Os tipos de dados na linguagem C so: Tipos de Dados Bsicos no C Definio no MPI MPI_CHAR MPI_INT MPI_FLOAT MPI_DOUBLE MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_LONG_DOUBLE Definio no C signed char signed int float Double Unsigned short int Unsigned int Unsigned long int long double

epolevnE odaD

Endereo (origem ou destino). composto por trs parmetros:

Informao que se deseja enviar ou receber. representado por trs argumentos:

185

MPI_LONG MPI_UNSIGNED_CHAR MPI_SHORT MPI_BYTE MPI_PACKED Rank

Signed long int Unsigned char Signed short int -

Todo o processo tem uma identificao nica atribuda pelo sistema quando o processo inicializado. Essa identificao contnua representada por um nmero inteiro, comeando de zero at N-1, onde N o nmero de processos. utilizado para identificar o processo destinatrio de uma mensagem, na operao send, e o processo remetente de uma mensagem, na operao receive. Group Group um conjunto ordenado de N processos. Todo e qualquer group associado a um communicator muitas vezes j predefinido como "MPI_COMM_WORLD". Inicialmente, todos os processos so membros de um group com um communicator. Communicator O communicator um objeto local que representa o domnio (contexto) de uma comunicao (conjunto de processos que podem ser endereados).

Primitivas Bsicas MPI


A seguir sero apresentadas as primitivas bsicas de MPI. MPI_Init(&argc , &argv) Inicializa uma execuo em MPI, responsvel por copiar o cdigo do programa em todos os processadores que participam da execuo. Nenhuma outra funo MPI pode 186

aparecer antes de MPI_INIT. argc, argv so variveis utilizadas em C para recebimento de parmetros. MPI_Finalize() Termina uma execuo MPI. Deve ser a ltima funo em um programa MPI. MPI_Comm_Size(communicator , &size) Determina o nmero de processos em uma execuo. communicator indica o grupo de comunicao e &size contm, ao trmino da execuo da primitiva, o nmero de processos no grupo. MPI_Comm_Rank(communicator , &pid) Determina o identificador do processo corrente. communicator indica o grupo de comunicao e &pid identifica o processo no grupo. MPI_Send (&buf, count, datatype, dest, tag, comm) Permite a um processo enviar uma mensagem para um outro. uma operao no bloqueante. O processo que a realiza continua sua execuo. Os parmetros so:

&buf: endereo do buffer de envio count: nmero de elementos a enviar datatype: tipo dos elementos a serem enviados dest: identificador do processo destino da mensagem tag: tipo da mensagem comm:grupo de comunicao MPI_Recv (&buf, count, datatype, dest, tag, comm) Funo responsvel pelo recebimento de mensagens. uma operao bloqueante. O processo que a executa fica bloqueado at o recebimento da mensagem. Os parmetros so: &buf: endereo do buffer de recebimento 187

count: nmero de elementos a enviar datatype: tipo dos elementos a serem enviados dest: identificador do processo remetente da mensagem tag: tipo da mensagem comm:grupo de comunicao status: status de operao Exemplo de programa A seguir ser apresentado um programa simples, no qual um processo envia uma mensagem para um outro, que a imprime. #include <stdio.h> #include "mpi.h" main(int argc, char** argv) { int my_rank; /* Identificador do processo */ int n; /* Nmero de processos */ char c[5] ; MPI_Status status ; MPI_Init(&argc , & argv); MPI_Comm_Rank(MPI_COMM_WORLD, &my_rank) ; MPI_Comm_Size(MPI_COMM_WORLD, &n) ; if (n != 2) exit() ; if (my_rank == 0) { strcpy (c, alo ) ; MPI_Send (c, strlen (c), MPI_CHAR, 1, 99, MPI_COMM_WORLD) ; else { MPI_Recv (c, 5, MPI_CHAR, 0, 99, MPI_COMM_WORLD, status) ;

188

Printf( %s\n , c) ; } MPI_Finalize(); } O programa acima formado por dois processos. Cada processo obtm sua identificao (my_rank) e se o numero de processos for diferente de 2 o programa termina ( para ser executado por dois processos). O processo 0 envia uma mensagem contendo alo para o processo 1 com a primitiva Send. O processo 1 recebe a mensagem, primitiva Recv, e a imprime.

Modelos de programas paralelos


Um programa paralelo composto por processos comunicantes que executam em processadores diferentes e que cooperam para a resoluo de um clculo. Os modelos que podem ser utilizados pelo programador para o desenvolvimento de suas aplicaes so: Diviso e conquista Esta tcnica consiste na criao de processos filhos para executar partes menores de uma tarefa. Os filhos executam e devolvem os resultados ao processo pai. Pipeline Os processos cooperam por troca de mensagens. Um conjunto de processos formam um pipeline, com a troca de informaes em um fluxo contnuo. Para enviar dados a um processo sobre um outro processador, o processo remetente deve agrupar os dados e remeter. O processo recebedor extrai os dados de uma mensagem recebida, processa e envia para o processo seguinte no pipeline.

189

Mestre/escravo O programa organizado como sendo formado por um processo (Mestre) que executa parte da tarefa e divide o restante entre os demais processos (Escravos). Cada escravo executa sua tarefa e envia os resultados ao mestre, que envia uma nova tarefa para o escravo. Pool de trabalho Um conjunto de tarefas depositado em uma rea acessvel aos processos componentes do programa paralelo. Cada processo retira uma parte de uma tarefa e executa. Esta fase se repete at que o conjunto de tarefas seja executado. Fases paralelas O programa paralelo formado por fases, sendo necessrio que todos os processos terminem uma fase para passar a fase seguinte. Mecanismos de sincronizao (ex. barreiras) so usados para que um processo espere pelos demais para passar fase seguinte. Com MPI possvel elaborar programas utilizando-se dos modelos acima apresentados. A seguir sero apresentados dois programas, um com o modelo Mestre/Escravo e outro um Pipeline. Programa mestre/escravo No programa a seguir um processo (o mestre) obtm valores, envia para os escravos calcularem a fatorial, recebe os clculos e os imprime.
include "mpi.h" main(argc,argv) int argc; char **argv; { int numero, i, fat=1 int myrank, size; MPI_Status status;

190

MPI_Init (&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); MPI_Comm_size(MPI_COMM_WORLD,&size); if (myrank==0){ printf("Sou o processo 0 \n"); for(i=1; i<4; i++){ scanf(%d, &numero); printf("Numero: %d \n",numero); MPI_Send(&numero,1,MPI_INT,i,99,MPI_COMM_WORLD); } for(i=1; i<4; i++){ MPI_Recv(&numero,1,MPI_INT,MPI_ANY_SOURCE,99,MPI_COMM_WORLD, s&tatus); printf("resultado: %d \n",numero); } } else { if (myrank==1) { printf("Eu sou o processo 1 \n"); MPI_Recv(&numero,sizeof(int),MPI_INT,0,99,MPI_COMM_WORLD,&st atus); for(i=1; i<numero; i++) fat = fat*i ; MPI_Send(&fat,1,MPI_INT,0,99,MPI_COMM_WORLD); } else { if (myrank==2) { printf("Eu sou o processo 2 \n"); MPI_Recv(&numero,sizeof(int),MPI_INT,0,99,MPI_COMM_WORLD,&st atus); for(i=1; i<numero; i++) fat = fat*i ; MPI_Send(&fat,1,MPI_INT,0,99,MPI_COMM_WORLD); } else{ printf("Eu sou o processo 3 \n"); MPI_Recv(&numero,sizeof(int),MPI_INT,0,99,MPI_COMM_WOR LD,&status); for(i=1; i<numero; i++) fat = fat*i ; MPI_Send(&fat,1,MPI_INT,0,99,MPI_COMM_WORLD); } } } MPI_Finalize(); }

O programa acima formado por quatro processos: o mestre e trs escravos. O mestre faz a leitura de trs valores e envia um para cada escravo, com a

191

primitiva Send, a seguir fica em um lao esperando pelos clculos dos escravos. Para o recebimento dos resultados, primitiva Recv, a identificao do remetente feita com MPI_ANY_SOURCE que permite o recebimento de mensagens de qualquer processo. Cada escravo recebe o valor do mestre (primitiva Recv), calcula a fatorial do nmero recebido e envia este resultado para o mestre. Programa Pipeline O programa a seguir apresenta o exemplo de um pipeline.
#include "mpi.h" main(argc,argv) int argc; char **argv; { int numero; int myrank, size; MPI_Status status; MPI_Init (&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&myrank); MPI_Comm_size(MPI_COMM_WORLD,&size); printf("Ola... \n"); if (myrank==0) { printf("Sou o processo 0 \n"); scanf(%d, &numero); MPI_Send(&numero,1,MPI_INT,1,99,MPI_COMM_WORLD); MPI_Recv(&numero,1,MPI_INT,2,99,MPI_COMM_WORLD,&status); printf("Sou o processo 0, recebi do processo 2 o valor%d \n", numero); } else { if (myrank==1) { printf("Eu sou o processo 1 \n"); MPI_Recv(&numero,sizeof(int),MPI_INT,0,99,MPI_COMM_WORLD,&st atus); numero = numero + 10 ; MPI_Send(&numero,1,MPI_INT,2,99,MPI_COMM_WORLD); } else { printf("Eu sou o processo 2 \n"); MPI_Recv(&numero,sizeof(int),MPI_INT,1,99,MPI_COMM_WORLD,&st atus);
,

192

numero = numero + 10 ; MPI_Send(&numero,1,MPI_INT,0,99,MPI_COMM_WORLD); } } MPI_Finalize(); }

No programa acima so criados trs processos. O processo 0 obtm um valor e o envia para o processo 1. O processo 1 adiciona um outro valor ao recebido e envia ao processo 2, que adiciona um valor ao recebido e envia para o processo seguinte no pipeline, que no caso o processo inicial (0).

Compilao e execuo de programas


A compilao de programas escritos na linguagem C (C++) feita com o comando mpicc [fonte.c] -o [executvel] [parmetros] onde o comando mpicc aceita todos os argumentos de compilao do compilador C. A execuo feita com o comando mpirun -[argumentos] [executvel] Os argumentos so: h arch machine np leave_pg nolocal t dbx executado - Inicializa o primeiro processo sobre o dbx - Mostra todas as opes disponveis - Especifica a arquitetura da(s) mquina(s) - Especifica a(s) mquina(s) - Especifica o nmero de processadores - Registra onde os processos esto sendo executados - No executa na mquina local

machinefile - Especifica o arquivo que contm o nome das mquinas

- Testa sem executar o programa, apenas imprime o que ser

193

Exemplos: mpirun -np 5 teste Executa o programa teste em 5 processadores mpirun -arch sun4 -np 5 teste Executa o programa teste em 5 processadores de arquitetura sun4.

MPI-2
Desde 1995 o Forum MPI comeou a considerar correes e extenses ao MPI padro. Em julho de 1997 foi publicado um documento que, alm de descrever MPI 1.2 e apresentar seus padres, define MPI-2. MPI-2 adiciona novas funcionalidades MPI, permitindo uma extenso aos modelos de computao. Estas novas funcionalidades permitem: Criao e gerncia de processos: so definidas primitivas que permitem a criao dinmica de processos. Comunicao com um nico participante: so definidas operaes de comunicao que so realizadas por um nico processo. Estas incluem operaes de memria compartilhada (get/put) e operaes remotas de acumulao. Extenses s operaes coletivas: novos mtodos de construir intercomunicators e novas operaes coletivas. Interfaces Externas: definido um novo nvel, acima de MPI, para tornar mais transparente objetos MPI. I/O Paralelo: so definidos mecanismos de suporte para I/O paralelo no MPI.

194

Linguagens: so definidas novas caractersticas de ligao de MPI com C++ e com Fortran-90.

Concluso
O estudo de MPI apresentado tem como objetivo iniciar o leitor no desenvolvimento de programas paralelos com o uso desta biblioteca de comunicao. Foram apresentados conceitos bsicos utilizados em MPI, as principais funes utilizadas para troca de mensagens e para inicializar e finalizar o sistema. Foram apresentados exemplos de programas em dois modelos de programao (mestre/escravo e pipeline) de maneira a permitir uma fcil compreenso.

Bibliografia
[BLA90] [CAV01] BLACK, D. L. Scheduling support for concurrency and parallelism in the Mach operating system. Computer. V. 5(23). May, 1990. CAVALHEIRO, G. G. H. Introduo programao paralela e distribuda. In: Anais I Escola Regional de Alto Desempenho. Gramado. 2001. FOSTER, YAN. Designing and Building Parallel Programs. Addison Wesley, 1995. GEIST, Al et al. PVM: Parallel and Virtual Machine- A User s Guide and Tutorial for Networked Parallel Computing. London: MIT, 1994 MPI-10 disponvel em http://www.mpi-forum.org , May 1994. MPI-2 disponvel em http://www.mpi-forum.org , May 1994. OLIVEIRA, R. S de; CARISSIMI, A. S e TOSCANI, S. S. Sistemas Operacionais. Porto Aleger: Sagra-Luzzatto. 2001 PACHECO, PETER. Paralllel Programming with MPI. Morgan Kaufmann Publischers, 1997.

[FOS95]

[GEI94]

[MPI94] [MPI97] [OLI01] [PAC97]

195

[POW91]

POWELL, M. L. et al. SunOS multi-thread architecture. In. Proc. of the Winter 1991 USENIX Technical Conference and Exhibition. Springer Verlag, LNCS 980. 1991. PVM Home Page disponvel em http://www.epm.ornl.gov/pvm/pvm_home.html , Nov. 2001 SEBESTA, R. W. Conceitos de linguagens de programao. Porto Alegre: Bookman. 2000.

[PVM 01] [SEB00]

Exerccios Bibliografia

196

7. Deadlock
Principios de Deadlock. Deteco e recuperao de deadlock. Preveno de Deadlock. Evitar Deadlock.

7.1 Princpios de Deadlock


Modelo de sistema Um sistema consiste de um nmero finito de recursos a ser distribudo entre um nmero de processos competindo pelos mesmos.

Recursos
So quaisquer entidades que puderem ocasionar bloqueio de processos. Um bloqueio ocorre quando um recurso no est disponvel e requisitado por um processo. Ex. de recursos: Dispositivos de E/S Memria regio crtica

Deadlock uma situao na qual processos esto bloqueados espera de recursos que jamais sero liberados

197

Exemplo clssico de deadlock: Supondo que o processo P1 requisite o recurso R1, execute algumas aes e requisite o recurso R2 e que o processo R2 requisite o recurso R2, execute algumas aes e requisite os recursos R1, como mostrado abaixo. P1: ... R (R1); ... R(R2); ... L(R1,R2) P2: ... R (R2); ... R(R1); ... L(R1,R2) O deadlock ocorre quando os dois processos adquirem o primeiro recurso que necessitam. No exemplo, se o processo P1 adquire o primeiro recurso R1 (R(R1)) e antes de obter o segundo recurso, o processo P2 adquire R2 (R(R2)), o sistema entra em deadlock, pois tanto P1 quanto P2 ficaro bloqueados a espera de um recurso que nunca ser liberado.

Tipos de recursos
Serialmente reusveis Constitudos de um nmero fixo de unidades idnticas, cada uma podendo ser utilizada de forma independente das demais. Aps uma unidade ter sido utilizada por um processo, pode ser reutilizada por outro, de forma serial. Cada unidade pode estar em um dos seguintes estados: alocada, disponvel. Recursos consumveis So constitudos por um nmero variado de unidades que so criadas e consumidas dinamicamente pelos processos. Os processos que produzem as unidades so denominados produtores e os processos que consomem as unidades so denominados consumidores. So caractersticas dos sistemas de processos cooperantes (trocas de mensagens, sinas de sincronizao)

198

Condies necessrias para a ocorrncia de deadlock [Coffman, et. al. System Deadlocks. ACM Computing Surveys, 1971].

1) Excluso mtua: o processo solicita o recurso para uso de forma mutuamente exclusiva. 2) Espera por recursos: Processos possuem recursos enquanto esperam por recursos adicionais. 3) No preempo: Quando os recursos no puderem ser confiscados temporariamente para serem alocados a outros processos. 4) Espera circular: Quando for possvel a formao de um ciclo no qual cada processo est bloqueado espera de recursos que esto alocados para outros processos de mesmo ciclo.

Mtodos para tratamento de deadlock 1- Detectar e recuperar 2- Prevenir 3- Evitar deadlocks

7.2 Detectar e recuperar deadlocks


Representao Uma aresta de um processo Pi para um recurso Ri significa a solicitao de uma unidade do recurso Ri. Uma aresta do recurso Ri para um processo Pi significa que o processo possui alocada uma unidade do recurso Ri.

199

Na figura acima, o processo P1 possui uma unidade do recurso R0 alocada. O processo P2 possui uma unidade do recurso R1 e est solicitando duas unidades do recurso R0. Na figura abaixo,

R0

P1

P2

P2 possui uma unidade do recurso R0 alocada, e p1 est solicitando duas unidades deste mesmo recurso.

possvel, pela anlise dos grafos, determinar se existe um deadlock. Existe deadlock se as requisies para alguns processos nunca sero atendidas

R oacola

1P 2P

oisiuqer

oacolA

200

Reduo de grafos uma maneira simples de examinar grafos para determinar se existe deadlock Um grafo pode ser reduzido em relao a um processo se todas as requisies do processo podem ser garantidas

Os processos que no podem ser reduzidos so os que esto em deadlock

Teorema: No existe processos em deadlock se e somente se o grafo completamente redutvel

R1

P1

R2

P2

Podemos reduzir o grafo por P1 porque suas requisies podem ser garantidas a reduo feita retirando-se as arestas de/para o processo

R0 P1

R1

201

P2

P2 pode agora ter suas requisies atendidas. Portanto, os processos podem adquirir os recursos de que necessitam e o sistema no entra em deadlock.

Algoritmo de deteco de deadlock Para um nico recurso com muitas unidades estruturas de dados vetor que representa o nmero de unidades necessrias para cada processo; varivel inteira, que representa o nmero de unidades do recurso disponveis.

Algoritmo AVAIL: nmero de unidades presentemente disponveis


nigeb rizuder levssop siam ajes on euq ta ritepeR )ssecorpforebmun ot 1=i( rof ,eslaf =: )i(decuder ;0=:ssecorpdecuder pool

202

Algoritmo para vrios recursos com vrias unidades por recurso matriz que representa as requisies dos processos
: qer

alloc : matriz que representa as unidades, de cada recurso, presentemente alocadas a cada processo avail : vetor que representa o nmero de unidades, de cada recurso, presentemente disponveis.

;1+ ssecorpdecuder =: ssecorpdecuder

;)ssecorpforebmun = ssecorpdecuder( =: decuderyletelpmoc

;)P(cola + liava =: liava

;eurt =: )P(decuder

;eurt =: noitcuder

{ neht )liava =< )P(qer( fi

{ )ssecorpforebmun ot 1 = P ( rof

{ ))P(decuder ton( fi

noitcuder ton nehw tixe ;eslaf =: noitcuder } } pool dne ;dne }

203

R0 0 P0 P1 P2 0 0 1

R1 1 0 0 0

R2 2 1 1 0 Avail

Requisio

P0 P1 P2

1 1 0

1 0 0

0 0 0

Alocao

Algoritmo para vrios recursos com vrias unidades por recurso

O algoritmo a seguir uma extenso do apresentado anteriormente, e detecta a ocorrncia de deadlock considerando um sistema com N recursos e cada recurso possuindo N unidades.
nigeb rizuder levssop siam ajes on euq ta ritepeR ;noitcuder ton nehw tixe )ssecorpforebmun ot 1=i( rof ,eslaf =: )i(decuder ;eslaf =: noitcuder ;0=:ssecorpdecuder pool

204

Quando executar o algoritmo: Quando uma requisio no pode ser satisfeita; 205

;1+ ssecorpdecuder =: ssecorpdecuder

;)ssecorpforebmun = ssecorpdecuder( =: decuderyletelpmoc

;eurt =: )P(decuder

{ )ssecorpforebmun ot 1 = P ( rof ;eurt =: noitcuder { ))P(decuder ton( fi

reducedbyp := true for (R = 1; R <= numberofressources; R++) { if req(P)(R) > avail(R) then { reducedbyp := false; } if (reducedbyp) {

for (R = 1; R <= numberofressources; R++) avail(R) := avail(R) + aloc(P)(R);

} pool dne ;dne }

Quando existe suspeita de deadlock Ex: Um processo est bloqueado h muito tempo a espera de recursos.

Recuperao de deadlock Quando o algoritmo de deteco de deadlock determina a existncia de um deadlock, muitas aes so possveis: a) Terminao de processos Terminar todos os processos. Esta ao implica em reexecuo do processo eliminado. Assim: o escolher uma vtima por vez at que o deadlock seja eliminado; o escolher criteriosamente o processo a ser terminado; o reexecutar o algoritmo de deteco. o Problema da reexecuo de um processo: nem sempre possvel ex. atualizao de base de dados. b) Preempo de recursos Recursos so retirados de processos no ciclo e entregues a outros, no mesmo ciclo, at que o deadlock seja eliminado. O problema a ser resolvido a definio de critrios para a escolha da vtima. c) Rollback Os processos possuem checkpoints em que, periodicamente, o estado gravado em um arquivo (imagem de memria, recursos); quando um deadlock detectado, o processo rolledback at antes de pedir um recurso;

206

o recurso atribudo a um outro processo no ciclo.

7.3 Prevenir a ocorrncia de deadlocks


Segundo Coffman, as quatro condies devem estar presentes para um deadlock ocorrer. A ausncia de uma condio impede a ocorrncia de deadlock. Portanto, previne-se situaes de deadlock eliminando-se pelo menos uma das condies necessrias para sua ocorrncia.

1)

Excluso mtua:

o processo solicita o recurso para uso de forma

mutuamente exclusiva. Esta condio eliminada se o processo solicita todos os recursos que necessita em uma nica vez. 2) Espera por recursos:. Processos possuem recursos enquanto esperam por recursos adicionais. Um processo pode requisitar e liberar recursos, mas quando requisitar um recurso no disponvel deve liberar os que estava utilizando e, ento solicitar todos coletivamente

3) No preempo:

Quando os recursos no puderem ser confiscados

temporariamente para serem alocados a outros processos. Elimina-se esta condio se os recursos forem ordenados e os processos devem requisitar os recursos em uma seqncia que respeite esta ordenao.

4) Espera circular: Quando for possvel a formao de um ciclo no qual cada processo est bloqueado espera de recursos que esto alocados para outros processos de mesmo ciclo. Esta condio eliminada se for

207

construdo um grafo e se for verificado, para cada requisio, se o atendimento no levar o sistema a um estado no seguro. As requisies que levarem o sistema a um estado no seguro ou de deadlock no devero ser atendidas.

7.4 Evitar deadlocks


Os recursos so requisitados quando necessrios e o sistema deve decidir se a requisio pode ser atendida sem gerar deadlock Os algoritmos necessitam que os processos declarem o mximo de recursos, de cada tipo, necessrios
.

Estado seguro/no seguro Se o sistema consegue alocar recursos para cada processo, em alguma ordem, e ainda evitar deadlock, o estado seguro. O estado seguro se existe uma seqncia segura O estado no seguro se no existe uma seqncia segura O estado de deadlock um estado no seguro Nem todo estado no seguro um estado de deadlock Com a informao de nmero mximo de recursos necessrios para cada processo possvel construir um algoritmo que assegura que o sistema nunca entrar em deadlock. O algoritmo examina dinamicamente o estado de alocao de recursos para assegurar que no existe uma espera circular. O estado de alocao definido pelo nmero de disponveis, alocados e demanda mxima de cada processo.

208

Algoritmo para evitar deadlocks O algoritmo que ser apresentado (Banker`s algorithm) baseado no estado e foi proposto pelo Dijkstra 1965. Proc Tape Printer Driver P0 P1 P2 P3 2 0 1 1 0 0 1 1 0 0 1 0

Matriz alocao P0 P1 P2 P3 1 2 0 1 1 1 0 0 1 1 0 1

Matriz necessidade P0 P1 P2 P3 3 2 1 2 1 1 1 1 1 1 1 1

Matriz mximo 1 0 0

vetor disponvel

209

Estrutura de dados Available: Vetor que indica o nmero de unidades disponveis de cada tipo de recurso Max: Matriz que define, para cada processo, o nmero mximo de unidades, de cada tipo de recurso, necessrias Allocation: Matriz que define o nmero de unidade, de cada tipo de recurso, alocadas presentemente para cada processo Need: Matriz que indica o nmero de unidades, de cada recurso, necessrias para cada processo (Max_Allocation)

Para uma requisio request (P,i) = k o processo P esta solicitando k unidades do recurso i if (request(P,i) <= need(P,i)) { if (request(P,i) <= available(i)) { available(i) = available(i) - k; allocation(P,i) = allocation(P,i) + k; need(P,i) = need(P,i) - k; } safe_state(); } else erro;

210

efas odatse mu me atse ametsis o

neht i odot arap eurt = )i(hsinif fi

;eurt = eunitnoc

; e u r t = ) i ( h s i n if

; ) i ( n o i t a c o l l a + ) i ( p m e t = ) i ( p m et

{ ) e s l a f = ) i ( h s i n i f d n a ) i ( p m e t = < ) i ( d e e n ( fi

;eslaf = eunitnoc

{ )eunitnoc(elihw

i odot arap

;eslaf = ]i[hsinif

;]i[elbaliava = ]i[pmet

Bibliografia

;eurt = eunitnoc

Exerccios

Safe_state: Estrutura de dados:

211
} } rotev :hsiniF rotev :pmet

8. Gerncia de Memria
Conceitos bsicos e Aspectos de hardware. Parties fixas. Parties variveis. Swapping. Paginao. Segmentao. Gerncia de memria no Linux e no Windows .

8.1 Conceitos Bsicos e aspectos de hardware


Memria central em sistemas de computador CPU e sistema de I/O interagem com a memria um conjunto (array) de bytes ou palavras, cada um com seu prprio endereo CPU faz busca e armazenamento na memria um programa deve ser carregado na memria para ser executado

Fig. 8.1 Interao CPU/ES/Memria

212

Memria fsica e Memria virtual Memria fsica a memria do hardware.Comea geralmente no endereo fsico 0 e continua at o maior endereo, que indica o tamanho da memria. Certas posies so reservadas pelo hardware para objetivos especiais (ex. vetor de interrupes) Memria virtual a memria que o processo enxerga. o espao virtual de um processo. O maior endereo virtual limitado pela arquitetura da mquina (No. de bits usados para enderear). O espao virtual pode ser maior que o espao fsico, especialmente se usada paginao/segmentao e um processo pode acessar qualquer parte de seu espao virtual.

Fig. 8.2 Espao de endereamento de um processo

Traduo de endereo O processo trata com endereos virtuais. Em todo acesso deve haver uma traduo de endereos, o que significa que a traduo no deve ser feita por software, o que inviabilizaria o desempenho do sistema. A figura a baixo representa o mapeamento entre a memria virtual e a memria fsica.

213

Fig. 8.3 Mapeamento entre a memria virtual e a memria fsica

Monoprogramao e multiprogramao Nos sistemas monoprogramados, existe um nico processo na memria em execuo e ao mesmo permitido usar toda a memria. Com multiprogramao existem vrios processos na memria aptos executar e um em execuo. Monoprogramao o esquema mais simples possvel: um processo por vez na memria; o processo pode usar toda a memria; a memria dividida entre o sistema operacional e o processo do usurio (figura a seguir).

SO Processo do usurio

odamargorponom lanoicarepo ametsis mu me airmem ad oazinagrO 4.8 .giF


214

Multiprogramao Com multiprogramao, vrios programas podem residir simultaneamente na memria, sendo que cada um executa por um determinado tempo. So necessrios mecanismos de proteo (hardware) para que um processo no acesse indevidamente a rea de memria de outro processo. Solues possveis para a implementao de proteo de hardware a utilizao de registradores para indicar o limite inferior e o limite superior da memria de um processo e de registradores base e limite. A figura a seguir ilustra o uso de registradores limite inferior e limite superior.

Ncleo Limite Inferior P0 P1 Limite Superior

Uso de registradores Limite Inferior e Limite Superior

Na figura acima so representados o ncleo do sistema operacional e dois processos, P0 e P1. Supondo que P0 esteja em execuo, o registradores Limite Inferior contm o valor do endereo mais baixo de memria ocupado por este processo e o registrador Limite Superior, o mais alto. A todo acesso a memria o hardware verifica se o endereo a ser acessado est entre estes dois valores. Em caso positivo, o acesso realizado. Caso contrrio gerada uma exceo, endereo invlido, e o processo terminado. Quando o processo P1

5.8 .giF

215

selecionado para execuo, estes registradores so carregados com os endereos de memria (inferior e superior) que o mesmo ocupa.

Registradores base e limite O uso de registradores base e limite uma soluo superior ao mtodo anterior (registradores Limite Inferior/Limite Superior), pois diminui o nmero de comparaes. Quando o processo selecionado, o endereo inferior de memria atribudo ao registrador base. A todo acesso a memria, o endereo de leitura ou escrita adicionado ao valor do registrador base. Se o endereo resultante menor ou igual ao valor do endereo limite (registrador Limite), o acesso realizado (endereo vlido). Caso contrrio, gerada uma exceo: endereo fora do espao de endereamento do processo. A figura a seguir exemplifica o uso de registradores base e limite.

Registrador Base

Limite

Endereo

<=
No Erro

Sim

memria

Uso de registradores base e limite na traduo de endereo

6.8 .giF

216

Com registradores limite muitos processos podem residir na memria simultaneamente. Duas polticas de gerncia de memria so Parties Fixas e Parties Variveis, apresentadas a seguir, podem ser implementadas com os mecanismos de hardware apresentados anteriormente.

8.2 Parties Fixas e Parties Variveis


Com o uso de Parties Fixas o sistema operacional divide a memria em um certo nmero de parties de tamanha fixo. Uma das parties ocupada pelo cdigo do sistema operacional, e as demais pelos programas de aplicao. O tamanho das parties somente pode ser alterado por um usurio com privilgios especiais (super usurio), na carga do sistema. Considerando uma memria de 128KBytes, a mesma pode ser dividida em 4 parties de mesmo de 32K. Neste caso, todas as parties possuem o mesmo tamanho. Outra alternativa dividir a memria existente em um certo nmero de parties de tamanhos diferentes. Por exemplo, pode-se ter uma partio de 32K para o SO, uma de 32 para processos pequenos (P0) e 1 de 64K para processos maiores (P1), figura abaixo.

SO P0

P1

Memria fsica organizada em trs parties de tamanha fixo

7.8 .giF

217

Para carregar um programa para execuo, o scheduler verifica sua necessidade de memria, que parties esto disponveis e carrega o processo em uma das parties com tamanho suficiente para cont-lo. O grau de multiprogramao, isto , o nmero mximo de processos em execuo simultnea, determinado pelo nmero de parties existentes. Em sistemas de partio fixa existem dois tipos de fragmentao: interna: tamanho da partio maior que o tamanho do processo. externa: partio no usada menor que o tamanho do processo esperando para ser executado. Em sistemas que utilizam parties fixas, quando os processos so

submetidos para execuo, alternativas para alocao de memria so: a) Classific-los de acordo com suas necessidades de memria (especificada pelo usurio ou pelo sistema) e coloc-los em uma nca fila de processoa aptos a rodar, de onde o escalonador os seleciona para execuo. Como as necessidades de memria e os tamanhos das parties so diferentes, problemas que podem ocorrer so: uma partio se torna disponvel e o primeiro processo da fila necessita de memria maior do que o tamanho da partio. Neste caso, o escalonador pode decidir selecionar um outro processo na fila (que deixa de ser uma fila). Esta soluo pode levar a postergao indefinida. Um outro problema que pode haver aumento de fragmentao interna a partio, na medida que processos pequenos podem ser carregados em parties grandes. b) Cada partio tem sua prpria fila de processos. Neste caso, pode-se ter uma fila com vrios processos esperando ser carregados para execuo em uma partio enquanto outra(s) parties de memria podem estar disponveis (fila vazia). 218

Parties variveis: O sistema operacional mantm uma tabela indicando que partes da memria esto disponveis e quais esto ocupadas. Inicialmente toda a memria esta disponvel, considerada como um bloco nico. Quando um processo chega e necessita memria pesquisado um bloco com tamanho suficiente para cont-lo. Quando um processo termina libera sua memria, que reincorporada ao conjunto disponvel. A figura a seguir ilustra uma memria organizada com o uso de parties variveis, com um bloco nico de 128 K disponvel.

Prim

128 K Ult

Parties variveis com um nico bloco disponvel

Supondo que um processo P0 foi submetido para execuo e que necessita de 12K, que um processo P1 necessita de 28K e que um processo P2 necessita de 8K, o mapa de alocao de memria mostrado na figura abaixo.

8.8 .giF

219

Prim

12K 28K 8K

Ult

80K

9 Parties variveis com blocos de diferentes tamanhos ocupados

Supondo que os processos P0 e P2 terminem e liberem a memria que possuiam, a lista de blocos disponveis fica composta por um bloco de 80K, que o primeiro, que aponta para um bloco de 12K, que aponta para um bloco de 8K, que o ltimo. O mapa de memria resultante mostrado na figura abaixo:

ocupados

.8 .giF .8 .giF

12K Prim 28K 8K Ult 80K

10 Parties variveis com blocos de diferentes tamanhos livres e

220

Caractersticas da poltica de parties variveis: existem blocos livres de diferentes tamanhos; se um bloco muito grande para um processo, dividido em dois, um alocado para o processo e o outro retorna para os blocos livres; quando um processo termina libera a memria, sendo esta colocada no conjunto de blocos livres; se o bloco liberado adjacente outro livre, podem ser agrupados formando um nico bloco. Em sistemas de partio varivel, existem trs alternativas para alocao de memria para os processos: first-fit: alocar o primeiro bloco da lista de blocos disponveis com tamanho suficiente para atender a requisio. O bloco alocado dividido em dois: o primeiro cujo endereo retornado ao requisitante e que contm o tamanho solicitado e um segundo bloco que deve ser acrescentado a lista de blocos disponveis, cujo tamanho a diferena do tamanho do bloco original e o tamanho de memria solicitada na requisio. best-fit: alocar o bloco de memria com o tamanho mais prximo do requisitado. O problema desta soluo que existe uma tendncia a gerao de fragmentos de memria pequenos. worst-fit: alocar o maior bloco de memria disponvel existente. Com esta tcnica, a idia gerar fragmentos grandes. A soluo mais utilizada para alocao de memria e que apresenta melhores resultados a first-fit. A pior a best-fit, pelo problema citado anteriormente. Um problema importante nos sistemas de parties variveis a fragmentao. Uma soluo utilizada a compactao, que consiste em unir os blocos de 221

memrias disponveis e de endereos adjacentes em um nico bloco, de tamanho maior. Considerando-se as polticas de parties fixas e parties variveis, apresentadas anteriormente, o hardware necessrio (registradores limite inferior/superior, registradores base/limite) permite a implementao de qualquer uma das polticas. O software que ir determinar o uso de uma ou outra. Para estas polticas, quando um processo selecionado, o dispatcher carrega os endereos de memria nos registradores. Ainda, a utilizao de memria geralmente melhor nos sistemas de parties variveis do que nos de parties fixas.

8.3 Swapping, Paginao e Segmentao


Nos polticas apresentadas anteriormente, parties fixas e parties variveis, os processos so carregados para execuo em uma rea contgua de memria, e somente ao seu trmino que esta memria liberada para ser alocada a um outro processo. Polticas que movimentam processos entre a memria e o disco, em tempo de execuo, so Swapping, Paginao e segmentao.

Swapping: Com esta poltica, os processos em execuo podem ser transferidos para disco para liberar memria, possibilitando desta forma a carga de outros processos para execuo. Desta forma, o nmero de processos em execuo simultnea formado pelos processos que esto na memria principal e pelos que esto na rea de Swap. O funcionamento desta poltica o seguinte: quando um processo submetido para execuo o sistema verifica a memria disponvel. No caso de no existir, um processo escolhido para ser levado para a rea de Swap, copiado da 222

memria principal para os endereos do disco que correspondem a rea de Swap (Swap out), assinalado no seu registro descritor esta situao e o novo processo carregado para a memria e introduzido na ready list. Quando um processo na rea de Swap selecionado para execuo deve ser carregado na memria principal (Swap in). Se necessrio, um outro dever ser levado para a rea de Swap para liberar a memria necessria. Desta forma, a ready list formada por processos na memria principal e na rea de swap. A rea de Swap ocupa uma localizao definida, alocada durante a

formatao do disco e de conhecimento do sistema operacional. Deve ser estabelecida de maneira a poder armazenar um grande nmero de processos, permitindo um alto grau de multiprogramao. Quando o scheduling decide executar um processo chama o select que verifica se o processo selecionado est na memria. Se no estiver, verifica se existe memria disponvel para acomod-lo. Se houver, dispara swap in do processo selecionado. Caso contrrio, dispara swap out de um processo escolhido para sair da memria e swap in do processo selecionado. A seguir, seleciona um outro processo que esteja na memria, restaura os registradores e transfere o controle para o processo selecionado. Nesta poltica, um aspecto importante o tempo de swap, que proporcional ao tamanho da memria a ser transferida. A medida que aumenta a velocidade de transferncia dos dispositivo, este tempo de transferncia diminui. Paginao Com o uso desta poltica de gerncia de memria, a memria fsica dividida em frames e a memria lgica divida em pages, de igual tamanho. Um programa para ser executado tem suas pages carregadas em frames disponveis na memria principal. O tamanho da pgina definido pelo hardware. Tamanhos caractersticos podem ser 1Kbytes, 2Kbytes, 4Kbytes.

223

O funcionamento desta poltica o seguinte: quando um processo deve ser carregado para execuo, o scheduling verifica o nmero de pginas que le precisa, verifica na lista de frames disponveis se existe um nmero suficiente, existindo, aloca para o processo. A seguir, o processo carregado para as pginas de memria fsica alocadas, e a sua tabela de pginas atualizada, de maneira a conter estes endereos. O endereo contido na instruo lgico e a cada acesso memria feita uma transformao do endereo lgico no endereo fsico correspondente. Transformao do endereo lgico para o endereo fsico O endereo gerado pela CPU contm duas partes: No. da pgina: (p) - enderea uma tabela de pginas; deslocamento: (d) - combinado com o endereo base da pgina define o endereo fsico de memria. Para a transformao de endereo lgico em endereo fsico (figura a seguir), a parte do endereo que contm a identificao da pgina usada para indexar uma tabela de pginas, que contm o endereo base da pgina. O deslocamento, combinado com o endereo base da pgina, indica a posio de memria a ser acessada. Endereo lgico P D

Memria fsica

11 Traduo de endereo com paginao

acisf oazilacol

ocisF oerednE

sanigp ed alebaT

f +D

.8 .giF

224

Alternativas para a implementao da tabela de pginas so: a) uso de um conjunto de registradores: recarregados como qualquer outro; carregados/modificados por instrues especiais.

b) na memria principal um registrador -page table base register-(ptbr) aponta para a tabela de pginas; c) uso de memria associativa (memria enderevel pelo contedo). A primeira soluo somente possvel de ser adotada se a tabela de pginas pequena. Para a soluo b, o tempo de acesso a uma posio de memria o problema. Para acessar endereo i os passos so os seguintes: 1. acessar tabela de pginas (uso do ptbr+ No.page desloc.) (1o. acesso memria); 2. o passo 1 produz um No. de frame que deve ser combinado com o deslocamento e que produz o end i; 3. acessar a posio i na memria fsica (2o. acesso). Portanto, so necessrios dois acessos a memria para obter a palavra desejada. A adoo de memria associativa otimiza os tempos de acesso a memria. Trata-se de uma memria mais rpida que a memria tradicional, porm, devido aos seus custos, normalmente so pequenas. Assim, contm poucas entradas da tabela de pginas. Um endereo lgico gerado pela CPU comparado com todas as entradas da tabela de pginas simultaneamente, a

225

qual contm nmero de pgina/nmero de frame (na memria associativa). Se o nmero da pgina encontrado, o nmero da frame usado imediatamente para acessar a memria. Se o nmero da pgina no encontrado, feito um acesso a tabela de pginas, na memria principal, para obter o nmero da frame que usado para acessar a memria. Neste caso, o nmero da pgina e o nmero da frame so colocados na memria associativa, de modo a ser encontrado rapidamente na prxima referncia

Compartilhamento de Pginas uma tcnica particularmente importante pois permite compartilhamento de memria e conseqentemente otimiza espao de armazenamento. O cdigo pode ser compartilhado entre diversos processos, sendo que os dados so privativos. Com esta tcnica, as tabelas de pginas dos processos que compartilham o cdigo possuem os mesmos endereos (apontam para as mesmas pginas) de memria principal. Exemplos de programas que compartilham cdigo so compiladores e editores de texto.

Segmentao Um programa um conjunto de subrotinas, funes, estruturas de dados (tabelas, etc.) que so referidos pelo nome. Cada um um segmento de tamanho varivel. Segmentao um esquema de gerncia de memria que suporta esta viso, sendo que cada segmento tem um nome e um tamanho. O endereo especificado pelo nome do segmento e pelo deslocamento, em relao ao incio do segmento. Com o uso de segmentao, um endereo lgico formado por duas partes: uma usada para indexar uma tabela de segmentos, que contm o endereo

226

base do segmento e a outra o deslocamento, que combinado com o endereo base indica a posio fsica de memria.

Implementao da tabela de Segmentos A implementao da tabela de segmentos pode ser feita por: a) conjunto de registradores; b) tabela de segmentos na memria; c) uso de memria associativa para manter as entradas da tabela de segmentos mais recentemente usadas.

A primeira alternativa, a exemplo de paginao, somente vivel se a tabela de segmentos pequena. Para a segunda possibilidade, utiliza-se dois registradores: STBR (segment table base register): aponta para o endereo base da tabela de segmentos do processo; STLR (segment table length register): contm o tamanho da tabela de segmentos. A transformao de um endereo lgico (s,d) em um endereo fsico feita da seguinte maneira: Se (s < STLR ) ento S = s + STBR; endereo = S + d; seno

227

erro. A tabela de segmentos na memria requer dois acessos, como na paginao, para a transformao de um endereo lgico em um endereo fsico.

8.4 Memria Virtual


A idia com memria virtual dar ao programador a iluso de que ele possui uma memria principal muito grande, maior do que a existente. O aspecto principal nesta idia de que o endereo existente no programa distinto de localizao fsica. O programa em execuo possui uma memria virtual, na qual os endereos so lgicos. A traduo do endereo (lgico) para a localizao na memria fsica (endereo fsico) feita pelo sistema operacional, com o auxlio do hardware. Como a memria virtual do processo pode ser maior que a memria real, partes do programa esto na memria e partes esto em disco. Isto para o usurio transparente, pois o SO que trata da transferncia entre disco e memria. A implementao de memria virtual pode ser feita usando-se os mecanismos de paginao e segmentao. Os conceitos e algoritmos apresentados a seguir se referem a pginao. Para os algoritmos serem utilizados com segmentao, necessitariam tratar do tamanho do segmento, que varivel, sendo portanto mais complexos. Com paginao, o programa para ser executado necessita que somente uma pgina, a que contm o cdigo inicial do programa, esteja na memria. Somente quando necessria pgina ser transferida do disco para a memria. A cada pgina do processo so associados cinco bits: um que indica se a pgina est presente na memria cache, um de pgina referenciada, outro que indica pgina modificada, o bit de presena na memria principal e um bit de proteo, que indica se a pgina pode ser escrita ou somente de leitura. (figura abaixo).

228

12 Estrutura de uma entrada na tabela de pginas

Os bits de pgina refernciada e modificada so atualizados a cada acesso a memria. Quando a traduo do endereo lgico para o endereo fsico feita, a pgina referenciada pode se encontrar na memria fsica ou no. Se a pgina est na memria, o traduo se completa. Se a pgina est no disco, gerada uma interrupo, o processo que gerou a falta de pgina fica bloqueado a espera que a pgina seja transferida para a memria. O sistema operacional dever selecionar uma pgina, que dever ser removida da memria, para dar lugar pgina necessria. Se a pgina que ser removida tiver sofrido alterao, a mesma dever ser gravada em disco. Caso contrrio, a nova pgina poder ser gravada sobre a pgina escolhida para ceder lugar na memria principal. Aps esta transferncia, o bit de presena da pgina na memria alterado para indicar esta situao e o processo inserido na lista de processos aptos a rodar. Por exemplo considerando dois processos , P0 e P1, cada um com cinco pginas lgicas e uma memria principal formada por quatro pginas, poderemos ter a seguinte situao:

anigp ad oremN

etnesua/etneserP

oetorP

aicnrefeR

oacifidoM ehcac

.8 .giF

229

P0
A B 0 1

Tabela de pginas de P0
V V I I i v v i i i 1 3 0 2 0 1 2 3 4 0 1 2 3 4

P1
G F 0 1

Memria principal
h 0

A figura acima mostra que o processo P0 possui as pginas 0 e 1 presentes na memria principal (v na tabela de pginas) e as pginas 2, 3 e 4 no presentes (bit de presena i invlido). O processo P1 possui na memria principal as pginas 2 e 4. Se o endereo referenciado por P0 se refere a pgina 2, esta pgina no est presente na memria. Neste caso, o sistema operacional dever selecionar uma pgina da memria principal para ser substituda.

8.4.1 Algoritmos de substituio de pginas

.8 .giF

C D H E J I 1 2 3

2 3 4 2 3 4

Tabela de pgina de P1

12 Exemplos de Tabelas de pginas

230

O problema para o sistema operacional a escolha da pgina a ser substituda, que dever minimizar as interrupes por falta de pginas. A poltica de escolha da pgina a ser substituda (pgina vtima), pode ser local ou global. local quando a escolha entre as pginas que pertencem ao processo que gerou a falta de pginas. global quando a escolha feita considerando o conjunto completo de pginas existentes na memria. Algoritmo timo Considerando como critrio de algoritmo timo a minimizao do nmero de falta de pginas, o algoritmo timo necessita que se conhea o string de referncia (sequncia de referncia) futuro, para selecionar para substituio a pgina que ser necessria no tempo mais longnquo. Com isso, estaria se aumentando o tempo para a ocorrncia de uma falta de pginas. Para se obter esta informao, pode-se executar o programa e obter o string de referncia, mas a sequncia poder no se repetir, dependendo dos dados e das decises existentes no cdigo do programa. O algoritmo timo no implementvel, pois no tem como o sistema operacional saber quando uma pgina ser novamente necessria.

Algoritmo FIFO (primeira pgina a entrar na memria principal a primeira a sair) Com este algoritmo, a pgina a ser substituda a que est na memria h mais tempo. Para implementar este algoritmo necessria uma fila contendo as pginas de acordo com a ordem de chegada na memria principal. Quando ocorrer uma falta de pginas, a primeira pgina da fila ser substituda, independentemente se est sendo utilizada ou no. A nova pgina ser colocada no final da fila. Esta escolha poder interferir negativamente na performance do sistema, bastando para tal que a pgina escolhida esteja sendo referenciada. Este algortmo raramente utilizado.

231

Algortmo da Segunda Chance Este algortmo uma combinao do FIFO com o bit R. A pgina mais velha na memria, a primeira da fila, candidata a ser substituda. Se o bit R possui o valor 1 indicando que a pgina foi acessada no ltimo intervalo de tempo considerado, zerado, e a pgina vai para o final da fila, recebendo uma segunda chance. O algoritmo recomea a examinar novamente o bit R da pgina que agora a primeira da fila. No pior caso, todas as pginas da fila tm o bit R com o valor 1 e o algoritmo se transforma em FIFO. Algortmo de substituio da pgina No Usada Recentemente (NUR) Este algoritmo considera os bits R e M para a escolha da pgina que dever ser substituda. Considerando as classes abaixo:

Ser escolhida aleatoriamente uma pgina de menor classe existente e que no tenha sido referenciada no intervalo de tempo considerado. Algoritmo do Relgio As pginas na memria fazem parte de uma fila circular, que pode ser vista como um relgio. Quando ocorre uma falta de pgina, a pgina apontada (cabea da fila) avaliada. Se o bit R zero, a pgina sai da memria, cedendo 232

adacifidom on ,adaicnerefer oN adacifidom on ,adaicnerefeR adacifidom ,adaicnerefer oN adacifidom ,adaicnerefeR

odacifingiS

M tiB 0 1 0 1

R tiB 0 0 1 1

essalC 0 1 2 3

lugar pgina que necessita ser carregada e o apontador passa a pontar para a pgina seguinte. Se o bit R possui o valor 1, recebe o valor 0 e o apontador de pginas avana para a prxima pgina que ento avaliada. Portanto, o algoritmo funciona da seguinte maneira: Se R = 0 ento retira a pgina e avana o ponteiro Se R = 1 faz R = 0 e avana o ponteiro. Algoritmo de substituio da pgina Menos recentemente usada (LRU) Este algoritmo parte do princpio de que as pginas usadas recentemente voltaro novamente a ser usadas. Mantm uma lista contendo as pginas mais usadas na frente, e as menos utilizadas no final da lista. Em todo o acesso a memria esta lista atualizada. Ser substituida a pgina no final da lista, isto , a pgina que est a mais tempo sem ser acessada. Para implementar este algoritmo, pode ser considerado o bit R. Aintervalos regulares de tempo (por exemplo a cada interrupo), os bits R so zerados. Um contador do nmero de vezes que o bit foi resetado indica a utilizao da pgina. O conceito de conjunto de trabalho (Working Set) Com o uso de memria virtual, para iniciar a execuo de um novo programa somente a pgina que contm o ponto de incio de execuo necessria. A medida que a execuo avana, pginas no presentes na memria so necessrias, originando a execuo do algoritmo que trata essas falta de pginas. Localidade de referncia um conceito que considera que um processo referencia somente um conjunto de pginas em uma determinada fase de sua execuo. O conjunto de trabalho (working set) de um processo o conjunto das pginas mais recentemente referenciadas no ltimo intervalo de tempo t. Por exemplo, considerando a figura abaixo,

233

pelas pginas {6790}. Observe que as pginas 2,3 e 4, do WS no esto mais presentes no WS pois deixaram de ser acessadas. importante ressaltar que este conceito pode ser empregado para blocos de memria, que podem ser pginas ou segmentos. Em outras palavras, o working set de um programa W(k, h), o contedo de uma janela de tamanho h no string de referncia rK. O working set no tempo t W(t, r), o conjunto de pginas referenciadas pelo processo no tempo t. O problema da utilizao do working set para minimizar as transferncias de pginas determinar o tamanho da janela. Devero permancer na memria as pginas pertencentes ao working set, isto , pertencentes a janela. Quando uma falta de pgina ocorre deve ser encontrada uma pgina que no pertence ao working set para ser substituda. Uma forma que pode ser empregada com a utilizao do bit de referncia da pgina. A janela, isto , o tamanho do working set pode ser o nmero de referncias a memria em um certo intervalo de tempo. O bit colocado em 1 quando a pgina referenciada e zerado a cada intervalo de tempo (interrupo). Quando ocorre uma falta de pginas, se o bit de referncia da pgina possui o valor 1, esta pertence ao working set e no deve ser removida. Se o bit de referncia 0, a pgina no foi referenciada durante o ltimo intervalo de tempo e candidata a remoo.
,2 1

234

O primeiro working set (WS formado pelas pginas {23467} e o WS


)1

00993876099911148871130997766266000559992142376423
2 1

WS

WS

8.4 Gerncia de Memria no Linux e no Windows


O sistema operacional Linux gerencia memria utilizando paginao por demanda. Quando o usurio submete um programa para execuo, o arquivo contendo o cdigo executvel aberto e uma parte vai para a memria. As estruturas de dados so ajustadas para indicar que os endereos da parte do programa executvel que foram copiados para a memria se referem a memria fsica. O restante do programa fica em disco. Quando o programa em execuo necessita acessar um endereo no mapeado na memria fsica, o Linux transfere a pgina do disco para memria e o acesso pode ento ser realizado. Quando o processo necessita de uma pgina virtual (que est em disco) e no existe memria disponvel, o Linux necessita criar um espao para acomodar a pgina necessria. Se a pgina escolhida como vtima no foi alterada, pode simplesmente ser utilizada para armazenar a pgina virtual. Quando for necessria, poder ser carregada da imagem do processo em disco. Se a pgina foi alterada, o Linux a escreve no arquivo de swap. O Linux usa o algoritmo LRU (Menos Recentemente Usada) para escolha da pgina a ser substituda. Toda a pgina no sistema possui uma idade associada. Quanto mais a pgina acessada, mais jovem a pgina se torna. As pginas mais velhas (acessadas menos recentemente) so boas candidatas para swapping. Para o Linux, a tabela de pginas possui trs nveis. Uma entrada na tabela de pginas de nvel 1contm o deslocamento da tabela de pginas de nvel 2, que contm o deslocamento da tabela de pginas de nvel trs, que contm o endereo base da pgina de memria que, combinado com o deslocamento que faz parte da instruo, indica o endereo fsico. A implementao do Linux nas diferentes plataformas deve prover mecanismos de traduo entre os trs nveis de tabela de pginas. Para o kernel esta traduo dever ser transparente. Para alocao de pginas, o Linux usa o algoritmo Buddy. Este algoritmo tenta alocar um bloco com uma ou mais pginas. Os blocos de pginas 235

possuem tamanho que uma potncia de 2 (os blocos possuem tamanho de 1 pgina, 2 pginas, 4 pginas, ...) e existe uma lista de blocos didposnveis para cada tamanho de bloco. Quando uma requisio feita, o algoritmo procura por um bloco de pginas com o tamanho pedido. Se no encontra, procura alocar ento um bloco que possui o dobro do tamanho solicitado, e assim por diante, at alocar umbloco. Se o bloco alocado maior do que o solicitado, dividido de maneira a atender o pedido e o restante mantido como disponvel e inserido na lista correspondente ao seu tamanho. O bloco alocado ento retornado ao processo solicitante. A alocao de blocos de pginas pode levar a fragmentao de memria. O algoritmo de liberao de pginas tenta combinar os blocos liberados com blocos disponveis, de maneira a formar blocos maiores. Quando um bloco liberado, o algoritmo verifica se existe um bloco de mesmo tamanho com endereos adjacentes. Existindo so combinados de maneira a formar um nico bloco de tamanho maior. Este processo se repete agora com o bloco de tamanho maior, na lista correspondente. Gerncia de Memria no Windows O sistema de gerncia de memria no Windows NT (2000/XP) utiliza paginao por demanda e o algoritmo que trata falta de pginas usa um mecanismo denominado de clustering. Cada processo no Windows possui um espao de endereamento de 4GBytes. Este espao determinado pela capacidade de endereamento de uma mquina de 32 bits. Normalmente reservado para o cdigo do usurio 2GBytes (parte inferior), sendo que os 2GBytes restantes (parte superior) so para execuo do sistema operacional, em modo kernel. O programa do usurio utiliza a quantidade de memria necessria. O cdigo do programa e os dados so carregados para a rea destinada ao armazenamento do programa do usurio.

236

Quando ocorre uma falta de pgina, o gerenciador de memria carrega a pgina solicitada e algumas ao redor (clustering). Com isso, tenta minimizar a falta de pginas, carregando antecipadamente as pginas vizinhas pgina solicitada. Considerando-se o fenmeno de localidade de referncia, a carga das pginas vizinhas diminui a possibilidade de ocorrncia de falta de pginas, conseqentemente diminui o nmero de acesso a disco, o que contribui para aumentar a performance do sistema. Quando a memria RAM est toda ocupada, necessrio escolher uma pgina para ser substituda, isto , para ser gravada em disco, de maneira a liberar espao para a pgina necessria. O algoritmo de substituio de pgina sutilizado o LRU, com o uso do relgio. O nmero de pginas de um processo presentes na memria definido em funo de seu working set. Este nmero varivel, depende das necessidades dos processos e da quantidade de memria existente.

Exerccios
1. Considere um sistema em que a memria e gerenciada por uma lista encadeada de blocos disponveis, de diferentes tamanhos. Essa lista definida por uma estrutura de dados contendo o endereo base do bloco, o tamanho de cada bloco e um apontador para o prximo elemento da lista. Existem dois apontadores, um para o primeiro elemento da lista, e outro para o ltimo. Escreva o procedimento addr = allocmem (n), onde n o tamanho do bloco que deve ser alocado e addr contm, no retorno da chamada, o endereo base do bloco alocado. A tcnica de alocao a ser utilizada First-Fit (o primeiro bloco com tamanho suficiente). Escreva tambm o procedimento free(addr), sabendo que se o bloco a ser liberado for adjacente a um outro, os mesmos devem ser agrupados. 2. Compare Parties Fixas, Parties variveis e Swapping. 3. Discuta o escalonamento de processos em sistemas de gerncia de memria com parties fixas. 4. Justifique o uso de compartilhamento de pginas, e apresente um 237

exemplo de sua utilizao. 5. Considere um sistema em que uma memria de 2MB gerenciada em dez parties de tamanho fixo cada uma. Sabendo que no existem prioridades entre as parties, e que existem registradores base e deslocamento, defina a(s) estrutura(s) de dados necessria e descreva a carga um programa em uma partio livre. 6. A afirmao Parties fixas so mais eficientes que parties variveis, pois aproveitam melhor o espao de memria existente e permitem que, definindo-se um nmero elevado de parties, se tenha mais processos na memria est correta? Justifique sua resposta. 7. Considere um sistema em que uma memria de 64MB gerenciada com o uso de parties variveis. Faa uma figura representando trs processos na memria, com, respectivamente, 12MB, 8MB e 6MB e a lista de disponveis contendo dois blocos (defina os tamanhos). A seguir, faa uma nova figura considerando o trmino de um dos processos em execuo. 8. Compare parties fixas e paginao.

Bibliografia

238

9. Gerncia de Arquivos
Conceitos Bsicos. Armazenamento e recuperao de arquivos. Compartilhamento de arquivos e sinnimos. Mtodos de acesso. Estudo de casos: Gerncia de arquivos no Linux e no Windows 2000/XP.

9.1 Conceitos Bsicos


Arquivos so entidades lgicas mapeadas pelo sistema operacional em dispositivos fsicos, que possuem informaes definidas pelo proprietrio (dados e programas). Cada arquivo possui um nome e referenciado pelo mesmo. O sistema operacional possui suporte (chamadas de sistema) para manipulao de arquivos.

Tipos de Arquivos Os arquivos podem ser: Regulares: contm informaes dos usurios. Pode ser um arquivo texto, o cdigo de um programa, etc., bem como pode conter tambm um cdigo binrio. Diretrios: so arquivos mantidos pelo sistema e que implementam a estrutura do sistema de arquivos. Contm nomes de arquivos e os endereos nos quais cada arquivo est armazenado nos perifricos.

Acesso aos arquivos regulares

239

O sistema operacional oferece ao usurio uma interface, sob a forma de procedimentos de biblioteca, que permite a manipulao de arquivos. Os principais procedimentos so: Create: permite a criao de um novo arquivo. Delete: elimina um arquivo existente. Open: abre um arquivo para posterior utilizao. Close: fecha um arquivo que estava em uso. Read: acessa um arquivo para leitura de dados. Write: escreve dados em um arquivo. Append: acrescenta, no final de um arquivo A, dados armazenados em um arquivo B. Rename: troca o nome de um arquivo. Link: cria um nome alternativo para um arquivo.

Diretrios Diretrios so arquivos especiais, mantidos pelo sistema operacional, que contm informaes que permitem acessar os arquivos regulares. Informaes tpicas mantidas em um diretrio so: Proprietrio do arquivo Data de criao; Data de modificao; Data de acesso;

240

Direitos de acesso; Existncia de sinnimos; Contador de uso; Endereo dos dados no disco; Etc.

Um diretrio possui vrias entradas, uma por arquivo que pertence aquele diretrio. Cada entrada do diretrio contm: O nome e os atributos do arquivo; ou O nome do arquivo e um ponteiro para uma estrutura de dados com os atributos do arquivo. Estas alternativas so esquematizadas nas figuras a seguir.

Diretrio contendo o Nome do arquivo e seus atributos

...,oirteirporP

,oirteirporP

sotubirt A

emoN

...

241

B
sotubirtA

Diretrio contendo nomes de arquivos e um apontador para os atributos

Um sistema de arquivos pode ser organizado como possuindo um nico diretrio contendo os arquivos de todos os usurio ou com um diretrio por usurio. A organizao mais natural haver um diretrio por usurio, sendo que somente o proprietrio do diretrio deve ter direitos de acesso, e que pode estender estes direitos a outros usurios Com isso, os usurios tm seus arquivos protegidos contra acessos no autorizados. As figuras a seguir exemplificam estas alternativas.

sotubirtA

242

Diretrio

Arquivo

Arquivo

Arquivo

Arquivo

Sistema de arquivos com um nico diretrio

Diretrio

Usurio1

Usurio2

Usurio3

Usurio n

Arq1

Dir1

Sistema de arquivos com um diretrio por usurio

Na organizao com um diretrio por usurio, cada usurio pode criar arquivos regulares ou diretrios, formando uma estrutura hierrquica de arquivos (uma rvore de arquivos). Numa estrutura hierrquica, os nomes dos arquivos podem ser absolutos ou relativos. Absolutos: consiste do caminho desde a raiz at o arquivo. Por exemplo, /usr/home/cmc/livro/cap5 o nome completo do arquivo cap5. Relativos: utilizados juntamente com o conceito de diretrio corrente. Todos os nomes de arquivo que no comeam com o separador (/,\), so considerados relativos ao diretrio corrente. Ex. Se o diretrio corrente

243

mail, o comando Linux cp usr1 usr1_message copia o arquivo /usr/spool/mail/usu1 para o arquivo /usr/spool/mail/usu1_message. Um conjunto de primitivas do sistema operacional permite aos usurios a manipulao de diretrios. As principais so: Create: cria um novo diretrio; Delete: elimina um diretrio que no contm arquivos; List: lista o contedo de um diretrio (nomes de arquivos que pertencem ao diretrio); Rename: troca o nome de um diretrio.

9.2 Armazenamento e Recuperao de Arquivos


Os dados pertencentes aos arquivos so armazenados em dispositivos fsicos, no volteis. A alocao de espao pode ser: Alocao Contgua: O sistema operacional aloca uma rea contgua no dispositivo para conter os dados do arquivo. Assim, para um arquivo de 230Kbytes seriam alocados 230 blocos consecutivos de um Kbyte. Esta alternativa simples de implementar e o arquivo pode ser lido de maneira eficiente. Os principais problemas desta soluo so a determinao do tamanho do arquivo a priori e a fragmentao, isto , a rea alocada no utilizada. Lista encadeada: Os dados pertencentes a um arquivo so armazenados em uma lista encadeada de blocos do dispositivo. Por exemplo, com blocos de 1k, 1022 bytes armazenam informaes, dois bytes endeream o prximo bloco. Nesta soluo, para acessar uma determinada informao no bloco i (acesso

244

randmico) necessrio percorrer a lista encadeada at o bloco desejado, isto , percorrer os i - n blocos de dados do arquivo. Lista de blocos com tabela na memria: Cada apontador de bloco de disco armazenado em uma tabela, no descritor do arquivo. Quando o arquivo aberto, esta tabela vai para a memria (juntamente com o descritor). Para identificar um bloco no necessrio nenhum acesso a disco (acesso randmico). O acesso feito tabela na memria, o endereo do bloco recuperado e ento pode ser realizado o acesso ao bloco de dados, no perifrico.

Gerncia de blocos livres O sistema operacional possui um conjunto de procedimentos utilizados para a gerncia do espao disponvel nos perifricos, utilizados para o armazenamento de arquivos. Duas solues utilizadas so: Lista encadeada de blocos livres: O sistema operacional mantm uma lista encadeada de blocos livres. A alocao de um novo bloco para um arquivo feita retirando um bloco da lista de disponveis, e a liberao de um bloco o reincorpora a lista de disponveis. O inconveniente desta soluo a quantidade de blocos necessria para conter a lista. Por exemplo, com blocos de 1Kbyte e dois bytes para identificar um bloco livre, pode ser armazenado em um bloco 512 endereos de blocos livres. Logo, so necessrios dois blocos para enderear um Mbyte. Mapa de bits: Uma tabela (mapa de bits) contm o mapa de ocupao do disco, na qual os blocos livres so representados por um e os ocupados por zero. Assim, para um disco com n blocos ser necessrio um mapa de n bits.

9.3 Mtodos de Acesso


245

Os dados dos arquivos so armazenados em blocos de disco. O acesso aos dado, nas operaes de leitura e gravao, depende da forma de organizao utilizada. Acesso seqencial: os dados armazenados somente podem ser acessados seqencialmente. Para acessar o registro i necessrio ler os (i 1) registros anteriores. Por exemplo, se a posio corrente do arquivo n, a leitura do registro (n + 8) feita lendo todos os registros anteriores. Neste caso, a posio corrente passa a ser (n + nove), o que indica o prximo registro a ser acessado o nmero 9. Se for necessrio ler um registro anterior, o arquivo necessitar ser lido a partir no primeiro registro do arquivo.

Incio do arquivo Posio de acesso Arquivo de Acesso Seqencial

Final do arquivo

Acesso direto: Os dados pertencentes ao arquivo so organizados logicamente em registros que podem ser acessados diretamente, independentemente da sua

246

localizao fsica no disco. Uma funo de transformao, executada pelo sistema operacional, associa um endereo fsico a um nmero de registro lgico. Considerando um disco com blocos de um Kbyte e um arquivo com registros lgicos de 100 Bytes, no primeiro bloco de dados do arquivo podem ser armazenados os 10 primeiros registros lgicos. Assim, a leitura do registro lgico trs transformado em uma leitura, a partir do byte 200 e at o byte 299, no primeiro bloco de dados do arquivo.

Incio do arquivo read(i, &b) ; Mtodo de Acesso Direto

Final do arquivo

Na figura acima, na operao read, a posio de acesso i o resultado da transformao do nmero lgico do registro em nmero de bloco e deslocamento dentro do bloco.

Bibliografia

247

Anda mungkin juga menyukai