Projeto de MC104 - SISTEMAS OPERACIONAIS

Ambiente com Suporte à Multiprogramação

 

Objetivos do Projeto

Desenvolver um programa com base no Programa Exemplo de modo a explorar 02 conceitos em sistemas operacionais: a criação de processos bem como sua execução em um sistema multitarefa. Assim, dentre os objetivos deste projeto destacamos:

 

Aspectos Teóricos

A seguir são discutidos conceitos diretamente relacionados com o projeto e, deste modo, sua leitura é importante e será cobrada quando da apresentação. Caso o entendimento desses conceitos não se concretize procure reler e, se necessário, realizar pequenas experiências de programação até que ocorra o entendimento.

Duração de um Trecho de Programa

A duração da execução de um trecho de programa dentro do computador nunca pode ser medida com certeza. Primeiramente, um computador é uma máquina digital, então, sua realidade é a execução de uma série de passos simples e determinísticos. Mesmo supondo que estes passos sejam realizados em um segundo ou um nanosegundo, os mecanismos disponíveis para medição de tempo em um computador sempre vão apresentar alguma limitação. Além do mais, o próprio conjunto de passos necessários para medir o tempo causa um profundo efeito no tempo que está sendo medido. Os atos de "ler" o tempo do relógio do sistema e copiar em uma área de memória local, onde o processo pode ter acesso, requer uma quantidade de tempo.

Sistema Multitarefa

Olhando um sistema com um único processador (ou um multi-processador que executa processos múltiplos), no processamento multitarefa diferentes processos conseguem uma parte do tempo disponível do processador. Por exemplo, se três processos precisam executar, o sistema operacional deixará cada processo executar por uma fatia de tempo. Depois que cada processo acabar de usar o processador durante sua fatia de tempo, o ciclo se repetirá. Isto dará a ilusão que todos os processos estão executando concorrentemente, devido à velocidade de execução da CPU.

Comandos para trabalhar com Processos

man - comando através do qual pode-se obter auxílio a respeito de outro comando. Por exemplo, tente chamar "man gettimeofday" (gettimeofday é uma função que é discutida adiante e serve para a leitura de um relógio). Antes de examinar as chamadas de sistema usadas pelo UNIX para executar operações sobre processos, pode ser útil olhar vários comandos que serão úteis na execução deste e dos projetos restantes e dentre eles destacamos: ps e kill

ps - comando que permite ver informações sobre os processos que estão em execução naquele instante na máquina. Digitando ps em uma janela aparecerá uma lista de processos. Embora a maioria dos SOs Unix tenha este comando para relacionar os processos ativos, o mesmo pode ser diferente em cada SO. Execute o comando man ps para aprender mais sobre o comando que lista informações de processos.

kill - O segundo comando importante é o comando kill que é usado para enviar sinais a outros processos (sinais serão cobertos em outro projeto). Para usar este comando digite kill pid, onde pid é a identificação numérica associada a um processo que se quer sinalizar. O pid de um processo pode ser obtido através de vários métodos, mas o mais comum é usar o comando ps. Tenha cuidado com os pids submetidos ao comando kill, pode-se terminar a execução, por exemplo, do shell, que é o programa que processa os comando Unix submetidos após o logon.

Criando e Administrando Processos em C

Existem três chamadas de sistema comuns fornecidas pelo Unix para criar e administrar processos: fork, exec e wait. A primeira chamada é usada para criar processos, a segunda para carregar uma imagem de processo (programa) diferente e a última para esperar pelo término de um processo. Procure executar o comando man sobre estes comandos para informação mais específica.

fork(...) - A chamada fork cria um processo novo. O novo processo é idêntico ao original com exceção de uma diferença secundária, o valor de retorno da chamada fork(...) (há outras diferenças, mas neste momento não têm importância). Para o processo a chamada fork(...) retorna o "pid" do processo filho e para o processo filho a chamada fork(...) retorna o valor 0.

execx(...) - chamada de sistema utilizada para trocar a imagem da aplicação corrente, ou seja, o programa por um outro. É um comando primário para rodar uma aplicação que esteja presente no disco rígido. A típica seqüência de chamadas é fork(...) seguida de execx(...) para começar a rodar um outro programa. As várias diferenças da chamada execx(...) permitem que programas possam ser inicializados com diferentes opções. Consulte também o manual específico de cada sistema operacional (comando "man") para maiores detalhes.

wait(...) - chamada de sistema que força o pai de um processo filho aguardar (em bloqueio) pelo fim da execução de seu filho. Quando um filho existe, wait(...) retorna o pid do filho que terminou. Se o ponteiro status for diferente de NULL, a informação de como o processo filho terminou será copiada na posição apontada por status.

 

Descrição do Projeto

Com base no código fonte do Programa Exemplo desenvolva as seguintes tarefas:

A primeira parte da tarefa é entender, compilar e executar as instruções disponíveis no Programa Exemplo.

Executar o programa 10 (dez) vezes. Procure carregar o computador a cada execução, ou seja, aumentar a sua carga através da execução de um número maior de programas, e veja se o desvio aumenta. Explique o que fez para aumentar a carga do computador e apresente os dez resultados obtidos. Analise os resultados obtidos destas execuções. Tente entender o que está acontecendo dentro da máquina!

Para a apresentação dos resultados do programa exemplo, crie um quadro semelhante ao apresentado em seguida. Analise os resultados e tente achar um padrão. Uma lição importante deste projeto é aprender que, quando há dormência de processos, o tempo de resposta dos processos não é previsível.

Filho

Total (mseg)

Média (mseg)

1

0.278

0.003

2

0.519

0.003

3

0.332

0.003

Se estiver interessado, tente mudar algumas das constantes e veja como elas afetam os resultados.

Com base no exemplo, altere o programa de maneira que o número de processos filhos seja lido pelo processo pai a partir do teclado. O número de microsegundos para a chamada usleep (...) deve ser crescente e ser igual a múltiplos de 100, isto é, se o primeiro processo filho chamar usleep(...) por 500microsegundos, o segundo processo filho deve chamar por 600microsegundos, o terceiro por 700microsegundos e assim por diante. Além disso, os filhos não mais calcularão o desvio, mas continuarão a chamar usleep (...) e depois devem ficar em um loop infinito do tipo CPU-bound (isto é, fazendo "espera ocupada").

Execute o programa modificado dez (10) vezes e crie um quadro adequado para apresentar os resultados. Analise os resultados obtidos e explique as diferenças.

Finalmente, inclua uma linha de comando ao final do programa modificado (após o trecho de código com a chamada de sistema kill para terminar os processos filhos) com uma invocação do processo pai à chamada de sistema sleep(...) por 15 segundos. Verifique a lista de processos ativos antes e depois de passados estes 15 segundos. Insira e remova o comando wait(...) após os comandos kill no programa, execute-0 novamente e volte a verificar a lista de processos ativos. Faça isto, se possível, no Linux e no Solaris. Analise os resultados e explique o que está acontecendo.

 


Luís Fernando Faina - faina@facom.ufu.br
Last modified: Tue Sep 5 14:49:56 2006