quinta-feira, 30 de junho de 2011

Exercicio de Revisão

  1. Os softwares estão divididos a principio em duas categorias. Quais são e em qual delas os Sistemas operacionais se enquadram e por quê?
  2. Porque a industria da computação resolver separa usuários do acesso direto ao hardware da maquina.
  3. Complete
A esta ............................., deu-se o nome ..........................., que nada mais é do que a ..........................de .......................... que fica entre o usuário e o hardware do computador, ou seja, o próprio ......................................
  1. O que são Micro Códigos em sistemas operacionais?
  2. São responsáveis por todos os dispositivos de hardware e endereçamento destes na memória da máquina. Também controlam o fluxo de entrada ou saída de dados, leitura ou escrita.
(   ) Registradores
(   ) Memória Ram
(   ) Disco Rígido
(   ) Memória Cachê

6.       Sistemas Operacionais

  1. Qual a principal função dos sistemas Operacionais?

  1. De que modo o Sistema Operacional e executado pela maquina e por que deve ser desta forma?

  1. Por que o Sistema Operacional é um gerente de recursos?

  1. Quais recursos estão disponíveis ao SO.

  1. Defina o termo TimeSharing?

  1. O que são arquivos e cite algumas características de arquivos?

  1. Explique como e por que ocorre o erro de DeadLock?

  1. O que são chamadas de sistemas, cite duas?

  1. O Windows e Unix se diferem de maneira  fundamental pelo método de programação utilizado. Explique isso?

  1. O que são sistemas operacioansi Multiusuarios?

  1. Qual a diferencça entre sistemas de tempo real e sistemas de tempo compartilhado?
  2. Quais eventos fazem com que um processo seja criado?
  3. O que são Daemons?
  4. Explique os motivos que levam um processo a ser finalizado?
   21. Explique a figura sobre estados de um processo?

  1. O que são Threads?
  2. Qual a diferença entre Thread e Processo?
  3. Explique por que acontece a condição de Disputa?
  4. O que é Região Critica?
  5. Qual a principal função do Gerenciador de memória. Explique?
  6. Quais as configurações de memória disponíveis e quais as suas aplicações?
  7. Explique o conceito de memória virtual?
  8. Paginação. Sabe-se que muitos programas trabalham com endereços virtual de alocação, e este endereço em algum momento devem ser gravados em disco. Como isso acontece?
  9. Quais as duas principais funções de um Sistema Operacional?
  10. O que é multiprogramação? Cite duas razões para se ter multiprogramação?
  11. O que é Spooling?
  12. Defina as propriedades essenciais dos seguintes tipos de Sistemas Operacionais:
    a. Batch
    b. Time-Sharing
    c. Tempo-real
    d. Distribuído
  13. Porque sistemas distribuídos são desejáveis?
  14. Qual é o propósito das chamadas de sistema?
 

segunda-feira, 27 de junho de 2011

Gerência de Memória

Devido aos Sistemas Operacionais apresentarem características variadas, determinados procedimentos tornam-se por vezes semelhantes ou próprios de cada Sistema. O gerenciamento de memória é um procedimento fundamental na objetividade de todos os Sistemas Operacionais.


A maioria dos computadores trabalha com o conceito de hierarquia de memória, possuindo uma pequena quantidade de memória  cachê, muito rápida,  uma quantidade de memória principal (RAM) e uma quantidade muito grande de memória de armazenamento em disco (HD), considerada lenta.

A memória é um dos itens mais importantes dentro de um computador, por isso a importância de um bom gerenciamento.

Gerenciamento (ou gestão) de memória é um complexo campo da ciência da computação e são constantemente desenvolvidas várias técnicas para torná-la mais eficiente. Em sua forma mais simples, está relacionado em duas tarefas essenciais:
  • Alocação: Quando o programa requisita um bloco de memória, o gerenciador o disponibiliza para a alocação;
  • Reciclagem: Quando um bloco de memória foi alocado, mas os dados não foram requisitados por um determinado número de ciclos ou não há nenhum tipo de referência a este bloco pelo programa, esse bloco é liberado e pode ser reutilizado para outra requisição.
ou melhor

      Os que não realizam paginação ou troca entre disco e memória
      O que não realizam este processo

O ideal seria, uma memoria que não precisasse deste artificios, uma memoria rapida, de grande capacidade e a um custo pequena. o que não acontece.

 O que se ve são varios tipos de memoria trabalhando paralelamente com os recursos computqacionais.

Assim,  devido a suas similariedade e caracteristicas distintas, as melhorias precisam de um meio para que possoam ser gerenciadas da melhor forma possivel. 

É uma estrutura que possui uma hieraquia devido suas caracteirsticas e atividades desenvolvidas.


  1. Cache (rapida e pequena, volatil, custo alto)
  2. RAM (velocidade media, tamanho medio e volatil, custo medio)
  3. Memorias Secundarias (velocidade lenta, tamanho grande e não volatil, custo baixo)
Tambem quando discutimos sobre gerencimento de memoria(GM), vimos que, apesar de seu crecimento exponencial com o tempo, cada vez temos mais memorias nos computadores modernos, temos do outro lado os programas cada vez mais exigentes com espaço, ou seja, cada vez temos programas maiores que a memoria disponivel.

A tendencia é que, com as interfaces graficas, os programas ocupem ainda mais as memorias. É um problema para os projetistas de Sistemas Operacionais que devem prever mecanismo de Gerenciamento de memoria mais eficientes possiveis.

 Outra questão esta realcionada as modalidades de programação distinta, tais como:

Monoprogramação sem troca de processos ou paginação

Um esquema mais simples de gerenciamento de memoria, onde a memoria é compartilhada entre o SO e os programas.

Podemos neste caso, possui tre configurações:


A 1ª configurações esteve presente nos Mainframes ou computadores de grande porte
A 2ª esta presente nos palmtops e outros computadores de mão
E a 3ª configuração esteve presente nos sistemas MS-DOS


Multiprogrmação com partições fixas


Atualmente, a monoprogramação não é mais utilizada, hoje, se um processo fica bloqueado esperando um recurso de E/S, outro processo podera esta utilizando a CPU naquele instante. Em sistemas Operacionais de rede, com varios usuários startando processos, isto bem evidente.

Esta habilidade presente somente neste sistemas operacionais rede, agora tambem faz parte dos sistemas dos usuários.

Como isso acontece, é realizado a divisão da memoria em n partições que pode ser feita manualmente. Quando um job chega, há duas possibilidades: ele é colocado em uma fila de entrada da menor partição capaz de armazená-lo ou ele é colocado em uma fila de entrada única.

 Como o tamanho das partições são fixas, se um job não ocupar todo o espaço da partição, este é pedido

Troca de Processos

Em sistemas computacionais modernos, usualmente, não há memória principal suficiente para armazenar os processos atualmente ativos. Desta forma, os processos excedentes são mantidos em disco e trazidos para a RAM quando necessário. Há duas formas de resolver este problema: troca e memória virtual, (sendo a última explicada posteriormente).

A operação de troca consiste em manter na memória alguns processos por um determinado período e, a seguir, trocar estes processos pelos demais que estão esperando em disco. A partição utilizada para cada processo pode ser fixa ou definida dinamicamente (de acordo com o tamanho do processo). Durante a operação de troca, é possível surgirem lacunas de memória que podem ser reunidas em um espaço maior através da técnica de compactação de memória.

No entanto, a atribuição dinâmica de memória conduz a um problema adicional: o gerenciamento de memória em relação a quais parcelas estão em uso e/ou quais estão livres. Existem duas formas de resolver este problema.

Gerenciamento de Memória com Mapas de Bits

Com mapas de bits, a memória é dividida em unidades de alocação. Cada bit do mapa representa uma unidade de alocação, sendo que se o bit for 0, a unidade está livre; caso contrário, a unidade está ocupada. Quanto menor for a unidade de alocação, maior será o mapa de bits e vice-versa. O maior problema com os mapas de bits é que procurar uma lacuna (seqüência de 0s) suficientemente grande para um determinado processo pode ser uma operação muito lenta.

Gerenciamento de Memória com Listas Encadeadas

Neste caso, é mantida uma lista encadeada com os segmentos de memória livres e encadeados. Uma possível configuração seria manter, em cada entrada, o endereço em que inicia, o seu comprimento e, evidentemente, o ponteiro para a próxima entrada.

Memória Virtual

Quando os programas excedem o espaço de memória física disponível para eles, é possível dividir o programa em pedaços chamados overlays. No entanto, isto exige que o programador seja responsável por esta divisão. De forma a facilitar o desenvolvimento de programas, passando esta tarefa para o Sistema Operacional, foi criado o método conhecido como Memória Virtual.

A idéia básica da memória virtual é que o tamanho combinado do programa, dos seus dados e da pilha pode exceder a quantidade de memória física disponível para ele, ou seja, neste caso, a simples troca, vista anteriormente, não resolveria o problema. O Sistema Operacional, então, mantém partes do programa atualmente em uso na memória principal e o restante em disco.

Paginação

Em qualquer computador, existe um conjunto de endereços que um programa pode produzir. Estes endereços gerados por programas são chamados endereços virtuais e formam o espaço de endereço virtual.

A MMU (Memory Management Unit) é responsável por mapear os endereços virtuais para endereços físicos de memória, sendo que consiste de um chip ou uma coleção de chips.
O espaço de endereço virtual é dividido em unidades chamadas páginas. As unidades correspondentes na memória física são chamadas molduras de página. As páginas e as molduras têm sempre exatamente o mesmo tamanho.

No espaço físico (memória) tem-se várias molduras de página. Por exemplo, podem existir 05 páginas situadas no espaço de endereço virtual que são mapeadas na memória física. No entanto, o espaço de endereço virtual é maior que o físico. As outras páginas não são mapeadas. No hardware real, um bit presente/ausente em cada entrada monitora se a página é mapeada ou não
.
Quando um programa tenta utilizar uma página não mapeada em uma moldura, a MMU detecta o acontecimento (que a página não está mapeada) e gera uma interrupção, passando a CPU para o Sistema Operacional. Tal interrupção é chamada falha de página. O S.O., então, seleciona uma moldura de página pouco utilizada e grava o seu conteúdo de volta ao disco, substituindo-a pela página requisitada.

Exercicio

1) Quais as duas principais funções de um Sistema Operacional?
2) O que é multiprogramação? Cite duas razões para se ter multiprogramação?
3) O que é Spooling?
4) Defina as propriedades essenciais dos seguintes tipos de Sistemas Operacionais:
a. Batch
b. Time-Sharing
c. Tempo-real
d. Distribuído
6) Porque sistemas distribuídos são desejáveis?
7) Qual é o propósito das chamadas de sistema?
8) O modelo cliente-servidor é popular em sistemas distribuídos. Ele pode ser usado em um sistema single-computer?
















      











    Produtor Comsumidor

    Codificação

            Este problema, chamado de Produtor-Consumidor (também conhecido como o problema do buffer limitado), consiste em um conjunto de processos que compartilham um mesmo buffer. Os processos chamados produtores põem informação no buffer. Os processos chamados consumidores retiram informação deste buffer.

            O mecanismo de comunicação entre processos utilizado foi a criação de uma pipe, a qual permite que um ou mais processos troquem informações entre si. O comando utilizado para a criação de novos processos foi fork(), que cria um processo filho retornado 0 e um processo pai retornando seu PID (Process ID).

    O código do programa implementado pode ser visto abaixo.

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <math.h>
     
    #define CONSUMIR 0
    #define ESCREVER 1
     
    char* phrase="a";  //caracter a ser colocado no buffer
     
    void main(){
     
    int fd[2], bytesRead, prod, consum, i, j, tipo, int_rand, cont;
    float rand;
     
    char message[100];
     
    printf("Entre com o numero de produtores:\n");
    scanf("%d",&prod);
     
    printf("Entre com o numero de consumidores:\n");
    scanf("%d",&consum);
     
    pipe(fd);
     
    do{
     
         for(i=0; i<prod; i++){
     
        if(fork()==0){
           close(fd[CONSUMIR]); // Fecha a ponta não usada
     
           //Processo produtor produz 50 ítens
     
           for(j=0; j<50; j++){
               write(fd[ESCREVER],phrase,strlen(phrase));
               printf("Item produzido por %d (%d produzido pelo processo).\n",getpid(),j+1);
               sleep(1);  //Dorme ao fim de cada produção por 1 segundo
           }
     
           break;  //Ao termino da producao, pula pra fora do laco que de criacao de produtores
           close(fd[ESCREVER]);
        }
         }
     
         if(i!=prod) break;  //Se nao for o primeiro pai, pula pro fim do programa
     
         for(i=0; i<consum; i++){
     
            if(fork()==0){
           close(fd[ESCREVER]);  // Fecha a ponta não usada
           cont=1; // Contador de itens consumidos pelo processo
     
           //Processo consome itens
     
           while(1){
              bytesRead=read(fd[CONSUMIR], message, 1);
              if(bytesRead>0){
            printf("Lido %d item por %d (%d lido pelo processo): %s\n",bytesRead, getpid(), cont, message);
                cont++;
              }else printf("Nao ha nada para ler.");
              rand=0.0001*random();
              int_rand=rand;
              usleep(int_rand);   //Processo dorme por um tempo aleatorio ao fim de um consumo
           }
           break;
           close(fd[CONSUMIR]);
        }
         }
     
         //Processo pai produz algo antes de terminar
         write(fd[ESCREVER],phrase,strlen(phrase));
         printf("Item produzido por pai com pid %d.\n",getpid());
     
    }while(0);
     
    }
     
           O programa inicia perguntando ao usuário o número de produtores e consumidores que ele deseja. Em seguida, é criada a pipe a ser utilizada. Inicia-se então um bloco de código com do. Isto foi feito para que, através de um break, um processo que já cumpriu sua função possa pular para o fim do programa, sendo assim encerrado.

          Em seguida, são criados os processos produtores. Convencionou-se que todos os filhos criados pelo pai original, inicialmente, fossem produtores. Cada produtor, assim que criado, produzia 50 ítens, esperando 1 segundo entre cada produção. Ao fim do cumprimento de sua tarefa, através de dois breaks, este processo ia para o fim do programa, assim terminando.

          Logo após foram criados os processos consumidores. Novamente convencionou-se que todos os filhos restantes criados pelo pai original fossem consumidores. Ao contrário dos produtores, que só produzem 50 ítems, os consumidores ficam tentando indefinidamente consumir. Esta diferença foi feita para que o programa fosse finito (não ficasse indefinidamente rodando). Quando o produtor não consegue mais consumir, ele apresenta uma mensagem.

          A questão das condições de disputa, neste caso, já são resolvidas pela própria estrutura da pipe, ou seja, suas operações de escrita e leitura garantem exclusão mútua.
     

    Algoritmo de Peterson

     O algoritmo de Peterson é um algoritmo de programação concorrente para exclusão mútua, que permite a dois ou mais processos ou subprocessos compartilharem um recurso sem conflitos, utilizando apenas memória compartilhada para a comunicação.

     Implementação

    Implementação do algoritmo em C:
    /*
                ***********  ALGORITMO DE PETERSON  ************
    */
     
    #include <stdlib.h>
    #include "rshmem.h" /*biblioteca não implementada*/
     
    void incrementa(int *mem, int k) {
       int i;
       i=*mem; TP
       i=i+k;  TP
       *mem=i;
    }
     
    int main(int argn, char **argv) {
       FILE *fsal;                   /*Ponteiro para arquivo com saída de resultados*/
       char *marcaFim,               /*Ponteiro fim de zona de memoria compartilhada*/
            *c1,                     /*Variavel de encerramento do processo-pai*/
            *c2;                     /*variável de encerramento do processo-filho*/
       int  *vez,                  /*Variável da vez de entrada do processo*/
            *recurso,                /*Ponteiro a zona de memoria compartilhada*/
            nIteracoes=0;          /*Contador de interações do processo*/
     
       /* Comprovação do número de argumentos */
     
       if(argn!=3){
          printf("Erro na entrada de argumentos/n");
          exit(1);
       }
     
       /* Abertura de arquivos */ 
     
       if((fsal=fopen(argv[2],"a+"))==NULL){
          printf("Erro ao abrir o arquivo de saída\n");
          exit(-1);
       }                /*Comprovação de abertura correta do arquivo de texto de entrada*/
     
       nIteracoes = atoi(argv[1]);
     
       /* criar zona de memoria compartilhada */
     
       if (!crearMemoria())
          fprintf(stderr, "Erro em criarMemoria\n");
     
       recurso  = (int *)  memoria ;
       turno    = (int  *) recurso  + sizeof(int);
       marcaFin = (char *) vez    + sizeof(int) ;
       c1       = (char *) marcaFim + sizeof(char);
       c2       = (char *) c1       + sizeof(char);
       *recurso =   0 ;
       *marcaFin = 'p' ;
       *c1='F';
       *c2='F';
     
       if (0!=fork()) {                               /* Processo Pai */
          int i;
          fprintf(fsal,"P1: SOU O PROCESSO PAI\n"); 
     
          for (i=0; i<nIteracoes; i++){
     
             *c1='T';                                /* Secção */
             *vez=2;                                     /*  de  */
             while (((*c2)=='T') && ((*vez)==2));           /*  entrada */
     
             incrementa(recurso, -5);                          /* Secção */
             fprintf(fsal,"P1: recurso[%d]=%d\n", i, *recurso);       /* critica */
     
             *c1='F';    /* Secção de salida */ 
     
          }/* fim do for */
     
          while (*marcaFim != 'x') ; /* Processo-pai espera processo-filho */
     
          fprintf(fsal,"O recurso que antes valia 0 agora vale %d\n", *recurso);
     
          if (!eliminarMemoria())   /* eliminar memoria compartilhada */
             fprintf(stderr, "erro em eliminarMemoria\n");
     
          exit(0);
     
       }/*if (0!=fork())*/
     
       else   {                                      /* Proceso filho */
          int i;
          fprintf(fsal,"P2: SOU O PROCESSO FILHO\n");
     
          for (i=0; i<nIteracoes; i++) {
     
             *c2='T';                          /* Secção */
             *turno=1;                                 /* de */
             while (((*c1)=='T') && ((*turno)==1));        /* entrada */
     
             incrementa(recurso, 5);                             /* Secção */
             fprintf(fsal,"P2: recurso[%d]=%d\n", i, *recurso);       /* critica */
     
             *c2='F';  /* Secção de salida */
     
          } /* fim do for */
     
      /* Encerramento dos processos */
     
          fclose(fsal);
     
      /* término */
          *marcaFim = 'x';
          exit(0);
     
       }/*fim do else Proceso-filho*/
       //{watchatcha/#}
    }/* *************** FIM MAIN ****************** */
    

    Regiões Criticas e Exclusão Mutua

          A condição de disputa acontece constantemente mas é evitada,  e os SO atuais constantemente verificam constantemente se um processo esta utilizando a mesma área de memória, o que, para o SO é proibido, para o SO um processo não pode lê ou escreve no mesmo espaço de memória,   um dos processo será excluídas antes que isso ocorra. Um processo conhecido como Exclusão Mutua.

            Durante a maior parte do tempo um processo execut5a computações internas que não requerem dados de outros processos. O trecho de programas onde ocorre o compartilhamento de dados com outros processos são chamada de Regiões Criticas. E para evita a disputa, estas áreas são monitoradas a todo momento, para evitar que dois processos estejam na mesma Região Critica.

            Assim, deve haver uma cooperação mutua entre os processos, o que deve satisfazer as seguintes condições:

          1.Não pode haver dois processos em regiões criticas

         2.Não são feitas suposições sobre a velocidade relativa dos processos e sobre o numero de UCPs.
          3.Nenhum processo parado fora da região critica pode para outros processos
          4.Nenhum processo deve espera um tempo arbritariamente longo para entra em sua região critica.
     
         Desabilitando Interrupções
         
         A forma mais simples de garantir a exclusão mutua e fazer com que cada processo ao entra na região critica desabilite as interrupções  e ao sair reabilite-as . Isto, impede que a CPU seja chaveada para outro processo e realize interrupções periódicas vindas do relógio da maquina  que ativa o escalonador de processo.
     
         Variáveis de Impedimento

        Pode-se também pensam em uma solução onde exista uma variável auxiliar, chamada  Lock Variable que indica ) para região critica livre e 1 para a mesma ocupada. Assim cada processo antes de entra em uma região critica, o mesmo checa esta variável.

        Alternância Obrigatória

         A solução pela qual um região deve ser entregue a um dado processo por vez é chamado de alternância obrigatória. E o teste continuo de uma variável a espera de um valor é chamado de Espera Ocupada. O que ocasiona um grande desperdício de CPU.
        
        O problema nesta solução e que os processos se alternem precisamente  e isto significa que o tempo dos processo devem ser exatamente iguais. Alem da desvantagem do processo que sai da região critica não poder mais retornar.
     
    Soluções para serem analisadas:

    Solução de Peterson
    Produtor Consumidor
    Semáforo
    Mutexes
    Monitores
    Troca de Mensagens
    Barbeiro Sonolento