1
Gerência de Processos Nos primeiros sistemas de computação somente um programa podia ser executado por vez, com acesso e controle pleno do sistema e seus recursos. A multiprogramação exige maior controle dos programas em execução. Resultou disto o conceito de processo, que é a unidade de trabalho de sistemas operacionais modernos de tempo compartilhado. Um sistema é uma coleção de processos: os de sistema operacional e os de usuário. Programas devem ser executados seqüencialmente.
Conceito de Processo Processo (Job, Tarefa) é o ambiente no qual um programa é executado. É formado por três partes: contexto de hardware, contexto de software e espaço de endereçamento. O contexto de hardware armazena o conteúdo dos registradores da UCP e dos registradores de uso específico, como o contador de programa (PC) – endereço da próxima instrução , ponteiro de pilha (SP) e registrador de status (SR). Uma das tarefas cruciais da mudança de contexto é salvar o contexto de hardware do processo preemptado e carregar os registradores com o contexto de hardware do processo selecionado para execução. No contexto de software são especificadas características e limites de recursos que podem ser alocados ao processo. Ele contém três grupos de informações: identificação (Process Identification, User Identification, etc), quotas (número máximo de arquivos abertos, tamanho máximo da memória principal e secundária, número máximo de operações pendentes de E/S, tamanho máximo de buffer, número máximo de subprocessos e threads) e privilégios (direitos). O espaço de endereçamento é a área de memória pertencente ao processo para instruções e dados.
nom e P ID o w n e r (U I D )
r e g i s tr a d o r e s g e r a is
p r io r id a d e d e e xe cu çã o d a ta / h o r a d e cr ia çã o
r e g i s tr a d o r P C
C o n te x t o d e S o f tw a r e
C o n te x to d e H a rd w a re
r e g i s tr a d o r S P
te m p o d e p ro ce ssa d o r q u o ta s Pro g ra m a
p r iv ilé g io s
r e g i s tr a d o r d e s ta tu s
E sp a ço d e E n d e r e ç a m e n to
e n d e r e ço s d e m e m ó r ia p r in c ip a l a lo ca d o s
Um programa é uma entidade passiva, enquanto um processo é uma entidade ativa. Dois processos podem ser associados ao mesmo programa. Por exemplo: vários usuários (ou mesmo
2 um) podem executar cópias diferentes do mesmo programa.
Estado do Processo Conforme um processo é executado, ele muda de estado
Estados comuns Novo: O processo está sendo criado Executando: As instruções estão sendo executadas Esperando: O processo está esperando que ocorra algum evento Pronto: O processo está esperando para ser atribuído a um processador Terminado: O processo terminou sua execução Este é um esquema básico e é implementado de formas mais detalhadas em cada caso. Apenas um processo pode estar em execução em cada processador a cada instante.
Bloco de Controle de Processo Também chamado Bloco de Controle de Tarefa ou Process Control Block (PCB)
3 Informações associadas a cada processo : Estado do processo, Contador de programa, Registradores da CPU , Informação de escalonamento de CPU, Informação de gerenciamento de memória (registradores de base e limite, etc), Informação contábil (quantidade de tempo de UCP utilizado, números de subprocessos, etc), Informação de status de E/S. O modelo clássico de processo considera implicitamente que exista um único fluxo de execução em cada processo. Nesta caso um usuário não poderia, por exemplo, utilizar abas em um navegador. Processos podem implementar múltiplos fluxos de execução, conhecidos como threads. Escalonamento de processos À medida que os processos são criados eles são colocados em uma fila de processos, com todos os processos do sistema. Os processos prontos são mantidos na fila de processos prontos (Ready queue), geralmente uma lista encadeada. Um cabeçalho mantém ponteiros para o primeiro e o último elemento e cada elemento tem um ponteiro para o seguinte. Existem as filas de dispositivo.
Uma representação comum é o do diagrama de filas
4
Processos Foreground e Background Um processo sempre está associado a pelo menos dois canais de comunicação, o de entrada e o de saída. Um processo foreground é aquele que permite a comunicação direta do usuário com o processo durante o processamento. Um processo background é o que não existe a comunicação com o usuário durante o processo. É possível associar o canal de saída de um processo ao canal de entrada de outro processo, criando um pipe.
Escalonadores O ato de selecionar processos para serem colocados nas diferentes filas é executado pelo escalonador (scheduler) adequado. Em um sistema em lote o escalonador de longo prazo ou escalonador de jobs seleciona processos do spool e carregaos na memória. O escalonador de curto prazo ou escalonador de UCP seleciona entre os processos prontos e aloca um deles para a UCP. Um escalonador de curto prazo é executado com freqüência, em geral pelo menos uma vez a cada 100 milissegundos. Se ele gastar 10 milissegundos a cada 100 milissegundos, 9% do tempo da UCP será desperdiçado com escalonamento. O escalonador de longo prazo pode ficar minutos sem ser executado. O escalonador de longo prazo controla o grau de multiprogramação (número de processos em memória). Um processo limitado por E/S (I/Obound) passa mais tempo em E/S do que utilizando a UCP. Um processo limitado por UCP (CPUbound) gera pedidos de E/S com pouca freqüência. Se todos os processos carregados forem limitados por E/S, a Ready Queue estará geralmente vazia. Se todos os processos carregados forem limitados por UCP, a fila dos dispositivos estará geralmente vazia. O escalonador de longo prazo precisa seleção rigorosa para balancear estas duas categorias. Em alguns sistemas, como os de tempo compartilhado, o escalonador de longo prazo pode estar ausente (como no Unix) ou ser mínimo. O equilíbrio destes sistemas depende de uma limitação física (número de terminais) ou da natureza de autoajuste dos usuários humanos, que simplesmente desistem de utilizar o sistema e se o desempenho atingir níveis abaixo do aceitável. Alguns sistemas introduzem o escalonador de médio prazo, pois às vezes é vantajoso reduzir temporariamente o grau de multiprogramação, reduzindo a disputa por UCP e recursos. Este esquema é chamado de swapping (troca). O swapping é realizado para melhorar a combinação de processos ou para liberar um recurso, como memória.
5
Troca de Contexto A tarefa de alternar a UCP entre processos é a troca de contexto ou mudança de contexto. O tempo de troca de contexto é overhead (custo adicional), pois o sistema não realiza qualquer trabalho útil durante a troca. Este tempo depende do hardware (velocidade da memória, número de registradores e instruções especiais que possam realizar a carga e armazenamento de registradores de forma mais eficiente). Costuma levar entre 1 e mil microssegundos. Alguns processadores Sun UltraSPARC fornecem distintos conjuntos de registradores e basta alterar um ponteiro para o conjunto atual.
Criação de Processo
Os processos pai criam processos filhos, que, por sua vez, criam outros processos, formando uma árvore de processos. Esta criação é feita por chamadas de sistema.
Um processo filho pode receber recursos diretamente do sistema operacional, obter um subconjunto dos recursos do processo pai ou mesmo compartilhar todos os recursos do processo pai Dados de inicialização podem ser passados do processo pai para o processo filho. Ao criar um processo filho o processo pai pode continuar a executar concorrentemente com o processo filho ou esperar até que alguns ou todos processos filhos tenham terminado. O espaço de endereçamento do processo filho pode ser uma duplicata do processo pai ou ter um programa carregado para ele. No Unix um novo processo é criado por uma chamada de sistema fork. O novo processo recebe uma cópia do espaço de endereçamento do processo pai. Ambos processos continuam a execução após o fork. O processo filho recebe um retorno zero do fork e o processo pai recebe o PID do processo filho. Ao receber um retorno zero (o que acontece com o processo filho), é executada a chamada de sistema execlp que carrega um novo programa na memória, destruindo a imagem na memória que contém a chamada de sistema execlp. O processo pai, se não tiver nada para fazer, pode emitir uma chamada de
6 sistema wait para sair da fila de processos prontos até o término do processo filho. Programa em C criando um processo separado #include <stdio.h> #include int main(int argc, char **argv) { int pid; /* cria outro processo */ pid = fork(); if (pid < 0) { /* ocorreu erro na execução do Fork */ fprintf(stderr, “Falha no Fork "); exit(1); } else if (pid == 0) { /* processo filho */ execlp("/bin/ls","ls",NULL); exit(1); } else { /* processo pai */ wait(NULL); /* pai espera o término do filho */ printf(“Filho terminou "); exit(0); } } No VMS da DEC, o processo cria um processo filho e carrega nele um novo programa. O Windows NT permite as duas abordagens.
Término do processo Um programa termina quando sua instrução final é executada, pedindo para ser excluído com a chamada de sistema exit. Ele pode retornar dados para o processo pai, que os receberá na chamada wait. Os recursos são desalocados. Um processo pode causar o término de outros por uma chamada de sistema como abort ou kill. Geralmente apenas o processo pai pode efetuar uma chamada destas em relação a um processo filho. Um processo pai pode fazer isso em decorrência de um processo filho exceder no uso de recursos, pela tarefa deste não ser mais exigida ou por estar terminando quando o sistema operacional não permite que um processo filho continue se seu processo pai terminar (término em cascata). No Unix, se um processo terminar sem conseguir “matar” os processos filhos, estes receberão o processo init como seu novo pai.
7
Processos Cooperantes ou Cooperativos Processos concorrentes podem ser independentes ou cooperativos Um processo independente não pode afetar ou ser afetado pela execução de outro processo. Um processo cooperante pode afetar ou ser afetado pela execução de outro processo. Vantagens da cooperação de processos: Compartilhamento de informações, agilidade na computação (subtarefas), modularidade e conveniência. O Problema do produtorconsumidor é paradigma para os processos cooperativos. Um processo produtor gera informações que são consumidas por um processo consumidor. Exemplos podem ser um programa de impressão e o driver da impressora ou um compilador e o montador. É preciso um buffer compartilhado entre os dois processos. O consumidor não pode consumir um item que não tenha sido completamente produzido. Há duas opções para o buffer. O buffer ilimitado (unboundedbuffer) não coloca qualquer limite prático no tamanho do buffer, permitindo que o produtor sempre possa produzir novos itens. O buffer limitado (boundedbuffer) considera que existe um tamanho de buffer fixo e o produtor terá de esperar se o buffer estiver cheio. O buffer pode ser fornecido pelo sistema operacional pelo uso de recurso de comunicação entre processos (IPC, InterProcess Communication) ou codificado pelo programador.
Comunicação Entre Processos O IPC é particularmente útil em ambientes distribuídos, como em um programa de chat ou mensagens instantâneas. O IPC é implementado por um sistema de troca de mensagens. O recurso de IPC oferece pelo menos duas operações: send(mensagem) – tamanho de mensagem fixo ou variável – e receive(mensagem). Mensagens de tamanho fixo são fáceis de implementar e dificultam a programação. O inverso ocorre com as mensagens de tamanho variável. Se os processos P e Q desejam se comunicar, eles precisam estabelecer um enlace de comunicação entre eles e trocar mensagens através de send/receive. A implementação do enlace de comunicação precisa de um lado físico (memória compartilhada, barramento do hardware) e lógico (propriedades lógicas). O arranjo lógico do enlace utiliza diversos métodos: ● Comunicação direta e indireta ● Comunicação simétrica e assimétrica ● Buffering automático ou explícito ● Envio por cópia ou referência ● Mensagens de tamanho fixo ou variável. Na comunicação direta um processo envia uma mensagem diretamente para o outro que precisa ser conhecido. Estabelecese um canal exclusivo e único a estes processos Comunicação direta com simetria de endereços: send(P, mensagem) receive(Q, mensagem)
8
Comunicação direta com assimetria de endereços: send(P, mensagem) receive(id, mensagem) Na comunicação indireta as mensagens são enviadas e recebidas por caixas de correio ou portas. Os dois processos precisam de ao menos uma caixa de correio em comum, que pode estar associada a outros processos. send(A,mensagem) – mensagem enviada para o caixa de correio A receive(A,mensagem) É importante avaliar o que aconteceria se mais de um processo tentar ler uma mesma caixa de correio. O esquema pode escolher entre permitir a associação de uma caixa a dois processos no máximo; permitir que no máximo um processo execute um receive ou identificar o destinatário. As caixas de correio podem ser propriedade de um processo ou do sistema operacional. Se pertencer a um processo é possível fazer a distinção entre o proprietário (que recebe mensagens nesta caixa) e os usuários (que enviam mensagens para a caixa). Se pertencer ao sistema operacional, este deve implementar métodos para criação, manipulação e exclusão de caixas. O processo que criar a caixa é o proprietário, embora vários destinatários possam utilizala.
Sincronização A troca de mensagens pode ser bloqueante (síncrona) ou nãobloqueante (assíncrona). Temos tanto envio bloqueante e envio nãobloqueante como recepção bloqueante e recepção nãobloqueante. Se ambos forem bloqueantes, configurase um rendezvous (encontro, em francês).
Buffering Fila temporária para envio de mensagens. Pode ser de capacidade zero (envio bloqueante obrigatório), capacidade limitada (envio fica bloquante se a fila estiver cheia) ou capacidade ilimitada (envio não bloqueante sempre é possível).