Preview only show first 10 pages with watermark. For full document please download

Aula6 So 2011-2

Mecanismo de Interrupção, Programação Concorrente e Programação concorrente - Memória Compartilhada

   EMBED


Share

Transcript

Sistemas Operacionais – 2011-2 AULA 5 – 31/08/2011 1. 2. 3. Mecanismo de Interrupção ....................................................................................................... 1 Programação Concorrente ........................................................................................................ 1 Programação concorrente - Memória Compartilhada ........................................................... 3 3.1. Implementando compartilhamento de memória – Linux ..................................................... 3 shmget .................................................................................................................................. 3 shmat .................................................................................................................................... 4 shmdt .................................................................................................................................... 4 shmctl ................................................................................................................................... 4 4. Exemplos ..................................................................................................................................... 4 5. Exercício – Fazer até o final da aula ........................................... Erro! Indicador não definido. 6. Referências Bibliográficas ......................................................................................................... 9 1. Mecanismo de Interrupção  Recurso comum dos processadores, sendo que através das interrupções o controlador de um periférico chama a atenção do processador e sinaliza a ocorrência de algum evento.  Provoca a execução de uma rotina especial, o tratador de interrupções, que é responsável por atender as interrupções.  Ciclo de execução de uma interrupção: - Prepara a transferência do controle para o tratador, salvando o contexto de execução do processo que estava usando a CPU. - Desvia o controle para o tratador. - Retorna a execução para o processo interrompido, restaurando o contexto de execução, sem que o processo perceba a interrupção. - O conteúdo de todos os registradores deverá ser o mesmo que no momento em que ocorreu a interrupção.  Existem momentos em que um programa não pode ser interrompido para evitar erros, como, por exemplo, se o programa estiver alterando variáveis. - SOLUÇÂO: desabilitar interrupção, pois enquanto estiverem desabilitadas serão ignoradas pelo processador (o processador tem o poder de habilitar e desabilitar interrupções).  Tipos de Interrupção: - Hardware: ocorrência de um evento externo ao processo (término de uma execução de E/S). - Software (trap): execução de uma instrução específica, sendo que o próprio programa interrompido gera a interrupção. Ex. chamadas de sistema. - Não é possível desabilitar interrupção de software. - Exceção: erros de execução (por exemplo, overflow).  Prioridade: as interrupções de maior prioridade são atendidas. Assim, as de menor prioridade podem ser desabilitadas até que as de maior prioridade tenham o atendimento concluído. - Interrupções de E/S tem prioridade maior em relação as de software.  Cada tipo de interrupção é identificada por um número, denominado valor de interrupção. 2. Programação Concorrente  Os processos podem ser: - Independentes: execução do processo não é afetada por outros processos em execução, ou seja, os processos estão executando em paralelo, mas não é programação concorrente. - A programação com processos independentes foi utilizada até o momento, pois os processos executavam paralelamente (pseudo-paralelamente), mas um não influenciava na execução do outro. - Cooperantes: pode afetar ou é afetado por outros processos em execução, assim, os programas que são implementados de forma a gerar esse tipo de processos são chamados de programas concorrentes.  Nos dois casos existe a proteção de memória, de forma que um processo de um usuário não corrompa/altere a área de memória dos processos de outro usuário.  Programação concorrente: - Vários processos cooperam para executar uma tarefa (conjunto de processos seqüenciais executando concorrentemente). - Vários processos disputam recursos (variáveis, periféricos e etc). - Existem vários fluxos de controle. - Necessidade de interação para a troca de informações. Ou seja, os programas concorrentes cooperam entre si (concorrem) para atingir um fim comum. - Por exemplo, ao executar um editor de textos 10 vezes (10 instâncias) não indica que o editor seja um programa concorrente, pois cada instância executa em uma área de dados própria, sem interação. - A interação pode ser por compartilhamento de memória ou troca de mensagens. - Algumas motivações - Aumento do desempenho: - Exploração do paralelismo real em máquinas multiprocessadoras. - Sobreposição de operações de E/S (exemplo da impressora (abaixo) ). - Compartilhamento de informações. - Motivação para a engenharia de software: facilidade de desenvolvimento de aplicações que possuem paralelismo intrínseco (servidor de impressão, so). Exemplo do servidor de impressão. - Desvantagens - Complexidade - Adicionam-se erros próprios do modelo aos erros comuns (diferença de velocidade na execução dos processos). - Difícil depuração (não-determinismo)  Programa concorrente vs seqüencial – exemplo Impressão. - Exemplo: Os dados devem ser lidos de um arquivo, colocados em um formato apropriado e enviados para a impressora.  Na programação seqüencial apenas um processo faz a leitura dos arquivos do disco e envia os dados para a impressora. - Impressora e disco nunca trabalharão juntos, por restrições do programa e não limitações eletrônicas. - Ex. Não haverá sobreposição de E/S, ou seja, enquanto está sendo realizada a leitura no arquivo o processo ficará bloqueado e a impressora ficará desocupada. Arquivo Impressora Processo Programa seqüencial acessando arquivo e impressora  No programa concorrente, dois processos compartilham um buffer, sendo que um deles lê os dados do disco e guarda no buffer e o outro retira os dados do buffer e envia para a impressora. - Disco e impressora poderão ser utilizados simultaneamente. - Podem existir limitações (ex. Um processo mais rápido que o outro). Arquivo Processo Leitor Buffer Processo Escritor Impressora Programas concorrentes acessando arquivo e impressora. 3. Programação concorrente - Memória Compartilhada  Shared Memory: forma mais rápida de IPC (inter-process communication) - Mecanismos de comunicação entre processos. Ex. Fila de mensagens, memória compartilhada e semáforos (sincronização).  Área reservada de memória na qual os processos trocam informações (mais que um processo tem acesso à mesma posição de memória).  Todos os processos enxergam e/ou alteram os dados guardados na área compartilhada, de acordo com as permissões.  Um processo cria o bloco de memória compartilhada e os demais se ligam ao mesmo endereço físico.  Os blocos devem ser liberados explicitamente quando não forem mais necessários. - O fim do processo não libera o bloco de memória.  É necessário garantir a sincronização no acesso à região de memória compartilhada (para isso podem-se utilizar semáforos). 3.1. Implementando compartilhamento de memória – Linux Fonte: http://www.ime.uerj.br/~alexszt/cursos/so1/MemCompart.pdf * Essa foi uma das fontes que usei.  Modo de armazenamento: - As várias regiões de memória compartilhada são armazenadas pelo kernel num local especial de memória - Region Table. - O kernel mantém um vetor (Shared Memory Table) em que cada entrada possui informação referente ao nome, permissões e tamanho da região correspondente, assim como o apontador para a Region Table.  Inclusão da biblioteca shm.h: #include  Chamadas de sistema (Unix/Linux) para a implementação de memória compartilhada: - shmget - Cria (ou utiliza) um segmento de memória compartilhada. - Retorna o identificador da área de memória ou –1 em caso de erro. - Sintaxe: shmget (key_t key, size_t size, int shmflg) - 1º argumento: Chave1 – valor inteiro longo que identifica a região de memória compartilhada. - 0 (IPC_Private): retorna uma área privada ao processo invocador, pode ser compartilhada entre pais e filhos (fork() ), mas nunca com processos implementados em programas distintos. - Número > 0: Chave que identifica a área a ser criada ou compartilhada. A região de memória pode ser compartilhada com qualquer outro processo, desde que o parâmetro chave seja igual. - 2º argumento: Tamanho do segmento (em bytes). - O tamanho do segmento de memória é definido no momento da criação e não pode ser alterado depois disso. - 3º argumento: Conjunto de flags. - 0666 (permissão): - Atribui a permissão de acesso à área de memória. No caso rw-rw-rw-. - Se for usado apenas esse flag no parâmetro, retorna o identificador associado à região de memória compartilhada chave, com as permissões indicadas. Caso a chave não exista, retorna erro. - IPC_CREAT|0666: 1 Para que não corra o risco de usar uma chave de outro processo (se um processo indesejado usar a mesma chave podem ocorrer erros ou outro processo podem acessar os dados indevidamente) pode-se usar a função ftok() para gerar chaves. Exemplo de página que fala sobre isso: http://jeiks.net/wp-content/uploads/2010/10/Exercicios_SD_Memoria.pdf - IPC-CREAT: utilizado junto com a permissão, cré utilizado para criar ou receber o identificador de uma área já existente, usando a permissão indicada. - Se a chave não existir, cria a região de memória compartilhada. Se chave existe, retorna o identificador associado à região de memória. - IPC_CREAT|IPC_EXCL|0666: - IPC_EXCL: quando o programa quer exclusivamente criar uma nova área de memória e não pegar o identificador de uma área existente. - Usando-se o IPC_EXCL associado ao IPC_CREAT: se a chave não existir cria a região de memória compartilhada e retorna a sua identificação, caso contrário retorna erro (-1). Verifica se uma dada região existe. - shmat - Liga o processo a área de memória compartilhada existente. - Retorna –1 em caso de erro. - Sintaxe: shmat (int shmid, const void *shmaddr, int shmflg) - shmid é o identificador da área de memória (retornado por shmget). - shmaddr identifica o endereço virtual (pertencente ao espaço de endereçamento do processo) onde deve ser feita a correspondência; - 0 – a correspondência será feita a partir do endereço inicial; - >0 - a correspondência é feita a partir do endereço especificado; - flags: permite escolher a permissão, de forma que não seja desrespeitada a permissão indicada em shmget.Se usar 0 será atribuída a mesma permissão usada no shmget quando a memória foi criada. - shmdt - Permite desligar uma região de memória compartilhada do espaço de endereçamento virtual do processo invocador. - Sintaxe: int shmdt(void *shmaddr) - O parâmetro shmaddr é o endereço virtual retornado por shmat. - shmctl - Oferece operações de controle. - Retorna –1 em caso de erro. - Sintaxe: shctl(int shmid, int cmd, struct shmid_ds *buf ) - shmid - é o identificador da área de memória. - cmd - especifica a operação que será realizada (IPC_RMID remove a área de memória especificada por shmid). - struct shmid_ds *buf - aponta para uma estrutura do tipo shmid_ds que é associada pelo sistema ao segmento de memória em que a operação será realizada.  Utilizaremos sempre NULL.  DICA Linux: - Para verificar os mecanismos IPC existentes no momento digite o comando ipcs. - Para excluir um mecanismo utilize o comando ipcrm ou ipcrm –M - nome do mecanismo: shm para memória compartilhada, sem para semáforo e msg para fila de mensagens. - id do mecanismo: id (nº inteiro) que é mostrado quando o comando ipcs é executado. - chave: id (nº inteiro) passado como parâmetro da função shmget ao criar a área de memória. 4. Exemplos – Compartilhamento de valores numéricos  Manipulação de uma mesma variável soma, pelos processos pai e filhos: #include #include #include int main(){ int *soma, x=3, y=3; int id_mem; /* identificador da memória comum */ //Cria uma área de memória compartilhada if ((id_mem = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT|0666)) == -1) { perror("Erro no shmget") ; exit(0) ; } // acoplamento do processo a zona de memória soma = (int *)shmat(id_mem, 0, 0); *soma = 10; if (fork()==0){ *soma = *soma + x + y; printf("\n\nNo filho1: soma = %d", *soma); puts(" "); exit(0); } if (fork()==0){ *soma = *soma + 10; printf("\n\nNo filho2: soma = %d", *soma); puts(" "); exit(0); } wait(0); wait(0); printf("\n\nNo pai: soma = %d", *soma); puts(" "); //Apaga a área de memória shmctl(id_mem, IPC_RMID, NULL); }  Manipulação de dois valores inteiros em uma mesma área de memória – pelos processos pai e filhos. #include #include #include int main(){ int *buffer=0, i, soma; int id_mem; if ((id_mem = shmget(IPC_PRIVATE, 2*sizeof(int), IPC_CREAT|0666)) == -1) { perror("Erro no shmget") ; exit(0) ; } buffer = (int *)shmat(id_mem, 0, 0); if (fork()==0){ *buffer = *buffer + 10; printf("\n\nNo filho1: primeiro inteiro= %d", *buffer); puts(" "); exit(0); } if (fork()==0){ buffer = buffer + 4; *buffer = *buffer + 5; printf("\n\nNo filho2: segundo inteiro= %d", *buffer); puts(" "); exit(0); } wait(0); wait(0); printf("\n\nNo pai: primeiro inteiro= %d", *buffer); puts(" "); printf("\n\nNo pai: segundo inteiro= %d", *(buffer+4) ); puts(" "); soma = *buffer + *(buffer+4); printf("\n\nNo pai: soma = %d", soma); puts(" "); shmctl(id_mem, IPC_RMID, NULL); } 5. Memória Compartilhada – compartilhamento de String  Declaração do ponteiro: char *buffer  A criação, ligação e remoção da área de memória compartilhada são feitas da mesma forma que para o compartilhamento de valores inteiros.  O acesso à área de memória é realizado com as rotinas memcpy: - Sintaxe: (*destino, *origem, bytes) - Biblioteca: string.h - Exemplos: - Guardar uma string (no máximo 20 bytes) no buffer (área de memória compartilhada): - memcpy(buffer, variavelString, 20); - Copiar 20 bytes do buffer na variável string: - memcpy(variavelString, buffer, 20); 5.1. Exemplo – Compartilhamento de Strings **Antes de executar os programas crie um arquivo chamado memstring.txt2, que será usado na função ftok() para a criação de uma chave a ser usada apenas na área de memória compartilhada nesse programa. Comando: touch memstring. escritor.c: cria a área de memória para armazenar 15 bytes e guardar uma palavra, digitada pelo usuário. #include #include #include #include int main(){ char *buffer, str[15]; int id_mem; /* identificador da memoria comum */ key_t chave; chave = ftok("arqstring.txt" , 10); if (chave == -1) { perror("Erro ao criar a chave"); exit(0); } if ((id_mem = shmget(chave, 15, IPC_CREAT|IPC_EXCL|0666)) == 1) { perror("Erro no shmget") ; exit(0) ; } 2 Pode-se usar o mesmo arquivo para vários programas, desde que o número indicado na função ftok() seja diferente. Ftok() é uma função que retorna uma chave, baseando-se no arquivo e no número indicados. /* acoplamento do processo a zona de memoria */ buffer = (char *)shmat(id_mem, 0, 0); puts("Entre com a palavra:"); gets(str); memcpy(buffer, str, 15); } leitor.c: se liga à área de memória e imprime a palavra guardada. * A área deve ficar sendo lida até que o usuário digite algo no programa escritor. * Conteúdo é igual a “ “ quando nada foi digitado. * Após imprimir a palavra apaga a área criada. #include #include #include #include int main(){ char *buffer, str[15]; int id_mem; /* identificador da memoria comum */ key_t chave; chave = ftok("arqstring.txt" , 10); if (chave == -1) { perror("Erro ao criar a chave"); exit(0); } if ((id_mem = shmget(chave, 15, 0666)) == -1) { perror("Erro no shmget") ; exit(0) ; } /* acoplamento do processo a zona de memoria */ buffer = (char *)shmat(id_mem, 0, 0); do{ memcpy(str, buffer, 15); }while(strcmp(str,"")==0); printf("\nPalavra = %s\n", str); /*Apaga a área de memória*/ shmctl(id_mem, IPC_RMID, NULL); }  No programa leitor existe o problema de buzzy waiting  a solução para isso será vista posteriormente. 6. Exercícios - reforço A. Faça dois programas que se comunicam usando memória compartilhada que realizam as seguintes ações: - escritor.c: cria a área de memória e salva um número, digitado pelo usuário, na mesma.  Ao criar a área de memória deve ser feita a verificação de que ela está livre. - leitor.c: se liga à área de memória e imprime o número guardado.  A área deve ficar sendo lida até que o número seja diferente de zero. Após imprimir todos os números apaga a área criada.  Ao ser criada a área de memória já é preenchida com 0 (zero). B. Faça dois programas que se comunicam usando memória compartilhada que realizam as seguintes ações: - escritor2.c: cria a área de memória compartilhada (buffer) para 5 valores inteiros e salva 5 números na mesma, digitados pelo usuário. - Ao criar a área de memória deve ser feita a verificação de que ela está livre. - leitor2.c: se liga à área de memória criada pelo escritor e imprime os 5 números guardados. Cada posição do buffer só é impressa quando possuir um valor diferente de zero. Após imprimir todos os números apaga a área criada. C. Altere o exemplo de forma que o escritor e o leitor trabalhem da seguinte forma: - escritor: cria a área de memória compartilhada (buffer) para armazenar 5 palavras, de até 20 bytes cada, digitadas pelo usuário. - leitor.c: se liga à área de memória e imprime as 5 palavras guardadas. Cada posição do buffer só é impressa quando possuir um valor diferente de “ “. Após imprimir todas as palavras, apaga a área criada.  Ao ser criada a área de memória fica com “ “ (branco). D. Faça três programas que se comunicam usando memória compartilhada que realizam as seguintes ações: - escritor1.c: cria uma área de memória (buffer1) compartilhada (buffer) para 5 valores inteiros e salva 5 números na mesma, digitados pelo usuário. - escritor2.c: cria outra área de memória (buffer2) para 5 valores inteiros e salva 5 números na mesma, digitados pelo usuário. - leitor.c: se liga às áreas de memória criadas pelos escritores e imprime a soma dos números guardados nas posições correspondentes dos buffers, criados nos escritores. Cada soma só pode ser realizada se os valores correspondentes já estiverem salvos nos buffers. Após imprimir todas as somas, apaga as áreas criadas.  Considere que os usuários digitarão valore diferentes de 0 (0). 7. Trabalho Individual *Valor: 1.5 **Entregar até o dia 14/09, sendo que: - Só serão considerados programas compilando sem erro e executando adequadamente. - Códigos iguais serão desconsiderados. Não aceito justificativa como “Fizemos juntos, você viu.”. Troquem ideias, mas não códigos. ***Defender antes da G1, o trabalho só terá validade se for defendido. - Poderão ser defendidos os códigos entregues até o dia 14/09. - Marcar hora para defesa. Lembre-se que, se todos deixarem para o mesmo dia não haverá tempo hábil. A. Faça um programa em que o processo pai cria dois processos filhos, que realizam as seguintes ações: - Pai: cria três áreas de memória, com capacidade para armazenar 5 valores inteiros cada e cria dois processos filhos. Após a morte dos filhos, soma os números em posições correspondentes na primeira e na segunda área e armazena na posição correspondente da terceira área. Por fim, imprime o conteúdo e mata as áreas de memória compartilhada. - Filho1: armazena 5 números distintos na primeira área de memória compartilhada (escolha como será o preenchimento, de forma que os números não sejam digitados pelo usuário). - Filho2: armazena 5 números distintos na segunda área de memória compartilhada (escolha como será o preenchimento, de forma que os números não sejam digitados pelo usuário e que o preenchimento seja diferente do realizado pelo filho2). B. Implemente três programas que executam ao mesmo tempo e se comunicam através de memória compartilhada, de acordo com as seguintes instruções: 1. Cadastro - Programa que solicita ao usuário o nome, o valor e a quantidade em estoque de 10 produtos e guarda em três áreas de memória compartilhada distintas. - Esse programa deve criar todas as áreas de memória compartilhada e deve ser executado antes que os demais programas. Caso outro programa execute antes que as áreas de memória sejam criadas, deve ser apresentada uma mensagem informando isso ao usuário e o programa deverá ser abortado. 2. Consulta - Oferece ao usuário as seguintes opções: imprimeTodos – Imprime os dados de todos os produtos que estiverem cadastrados nos buffers no momento da pesquisa. * Considere que essa consulta pode ser feita em vários momentos. Por exemplo, antes de preencher qualquer valor ou depois de preencher os dados de apenas 3 produtos. imprimeDados – Solicita uma posição no buffer [1 – 10] e imprime os dados do produto que está armazenado na posição escolhida. ?????????????? – Invente uma Opção e a funcionalidade referente a ela. Pode alterar o programa Cadastro, por exemplo, criar uma nova área de memória compartilhada. Sair – Encerra a execução do programa. 3. Encerra - Programa que deve ser executado após o encerramento dos dois anteriores e mata as áreas de memória compartilhada. 8. Referências Bibliográficas (conceitos)  OLIVEIRA, Rômulo Silva de; CARISSIMI, Alexandre da Silva; e TOSCANI, Simão Sirineu. Sistemas Operacionais. Editora Sagra Luzzatto. Porto Alegre, 2001