Introdução Inst tituto de Info ormátic ca - UF FRGS Sistemas Operacionais i Introdução à Programação Concorrente Aula 05 Em sistemas multiprogramados há interação entre processos para comunicação, que pode ser feita via compartilhamento de memória/arquivos evitar inconsistências i i de acesso compartilhado executar de ações de forma ordenada e determinística Concorrência Processos (threads) disputam recursos do sistema (no mínimo a ) Processos (threads) )podem afetar ou serem afetadas por outra Programação concorrente assíncrona Atividades podem ser interrompidas sem aviso prévio e de forma não determinística ti Dois problemas abordados: exclusão mútua e sincronização Sistemas Operacionais I Condição de corrida (race condition) ) Exemplo: reserva assentos em avião Situação onde o resultado final depende da ordem em que processos (threads) são executados Ocorre quando há acesso compartilhado em leitura-escrita ou escrita A ordem de execução é afetada pelo escalonamento P 1 P 1 n C 3 4. n 3D. Exemplo: reserva de assentos em avião int reservaassento() { int n; Mas é se acontecesse isso P 1 1 n C 4 3 P. n C Sistemas Operacionais I 3 Sistemas Operacionais I 4
Seção e exclusão mútua O problema do assento de avião revisitado Seção Trecho de código que não pode ser executado por dois ou mais processos simultaneamente sob pena de inconsistência de dados Gera condição de corrida em acessos em escrita a recursos compartilhados Exclusão mútua Consiste em garantir que se um processo está usando um recurso compartilhado os outros processos estão impedidos de fazê-lo Como garantir? Criando mecanismos para P 1 entra na seção P 1 sai da seção exclusão mútua. P 1 P sai da Entrar na SC seção Seção (SC) P Sair da SC P tenta entrar Bloqueado na seção Sistemas Operacionais I 5 int reservaassento() { int n; <Entrar na SC> <Sair da SC> P P 1 1 <Entrar na SC> <Entrar na SC> (estado bloqueado) 4 n C 3 6 <Sair da SC> 5 <Sair da SC> n 3D (estado apto ou bloqueado) Sistemas Operacionais I 6 Propriedades para mecanismos de exclusão mútua Como implementar primitivas de exclusão mútua? Exclusão mútua Dois ou mais processos não podem estar simultaneamente na seção Progressão Um processo fora da seção não pode impedir outro de entrar nela Espera limitadait Um processo não pode ficar esperando eternamente para entrar na seção Suposições Nenhuma suposição pode ser feita sobre a velocidade relativa de execução dos processos, nem de número de processadores Processo ou thread Com suporte de hardware Baseado em habilitação/desabilitação de interrupções Instruções atômicas (test-and-sett d t e swap) ) Sem suporte de hardware, i.é, em software puro Variáveis do tipo trava (lock) Algoritmo de Dekker Algoritmo de Peterson Algoritmo de Lamport Procedural Baseado em suporte por compiladores (monitores) Contexto de INF0114 Contexto de INF01151 Sistemas Operacionais I 7 Sistemas Operacionais I 8
Desabilitação de interrupções Variáveis do tipo trava (lock) Mecanismo em hardware (instruções do processador) Só há troca de contexto com a ocorrência de interrupções de hardware Conclusão de E/S, violação de proteção, temporização Problemas: Poder demais para um usuário!! Risco de perda de eventos Não funciona em multiprocessador/multicore, pois apenas a que realiza a instrução é afetada CLI; Desliga interrupções Seção STI; Ativa interrupções Sistemas Operacionais I 9 uto de Info rissimi -15-ago- Institu A. Car Mecanismo em software Uso de uma variável compartilhada que armazena dois estados Livre e ocupado while (flag == 1); flag = 1; flag = 0 Seção Problema: Viola a propriedade de exclusão mútua Condição de corrida na primitiva de entrada Solução: Fazer com que o while e a atribuição sejam feitas de forma indivisível com auxílio do hardware. Sistemas Operacionais I 10 Instruções especiais Uso de TSL para implementar variáveis do tipo trava (lock)) Mecanismo em hardware Processadores são projetados para uso em ambientes de programação concorrente Instruções assembly para leitura e escrita em posições de memória de forma atômica (indivisível). SWAP: swap (a, b) Executa a permutação de valores Compare and Store: cas r1, mem Copia o valor de uma posição de memória para um registrador interno e escreve nela o valor 1 Test and Set Lock: tst registrador, mem Lê o valor de uma posição de memória e coloca nela um valor não zero Intel x86 possuem a instrução assembly XCHG (xchg register,mem) - A. Car rissimi -15-août- Solução baseada em instruções especiais Variável para indicar uso da seção (livre:0; ocupado 0) Duas primitivas: iti lock(flag) ) e unlock (flag) Problemas: lock_t flag=0; lock(flag); Seção unlock(flag); entrada_seçao: tst register,flag cmp register,0 jnz entrada_seção saida_seção: mov flag,0 Inversão de prioridade Desperdício de tempo de processamento (spinlock ou trava giratória) Travamento, se não houver interrupção de tempo (livelock) Sistemas Operacionais I 11 Sistemas Operacionais 1
Inversão de prioridades Soluções para inversão de prioridade Uma thread de mais baixa prioridade impede a progressão de uma thread de mais alta prioridade Menos prioritário Mais prioritário lock(m) Troca de processo/thread unlock(m) lock(m) Para piorar: Outros processos/threads Situações indesejadas: Bloqueado ou fazendo busy wait (até quando?) thread ou processo Teto para prioridade (priority ceiling) Aumento da prioridade de uma thread para um valor pré-determinado sempre que ela adquirir uma trava (lock) Teto deve ser maior que a prioridade da maior thread Na liberação (unlock) a thread orna a sua prioridade original Herança (priority inheritance) A prioridade da thread que detém a trava é elevada ao nível da thread mais prioritária que solicita o recurso Elevação da prioridade só ocorre se houver risco de conflito Na liberação (unlock) a thread orna a sua prioridade original Sistemas Operacionais I 13 Sistemas Operacionais I 14 O problema da espera ativa Uma nova versão para lock e unlock Espera ativa ou busy wait Ficar testar testando continuamente se a variável de entrada (flag) foi liberada Desperdício de tempo de processamento Solução: Bloquear o processo (thread) até que alguém libere a seção Oferecido por primitivas mais elaboradas que fazem sleep: bloqueia um processo a espera de um recurso* Executado no lock quando o recurso não estão disponível wakeup: desbloqueia o processo que esperava por um recurso Executado no unlock, na liberação do recurso, quando há alguém a espera Recurso (caso particular) = seção Funciona? lock_t flag=0; lock(flag); Seção unlock(flag); lock: tst register,flag cmp register,0 jnz entra call sleep jmp lock entra: unlock: mov flag,0 call wakeup Sistemas Operacionais I 15 Sistemas Operacionais I
Semáforos Primitivas P(s) e V(s) Proposto por Dijkstra (1965) Mecanismo para contar o número de sinais de acordar para uso futuro Semáforo é um tipo abstrato de dados: Um valor inteiro: contabiliza o número de sinais de acordar Fila: processos que esperam sinal de acordar associado a este semáforo Duas primitivas: P (Proberen, testar) similar ao sleep V (Verhogen, incrementar) similar ao wakeup Disponibilizadas para a usuários (programas as aplicativos) Introduzidos a primeira vez em Algol 68 com os nomes down e up. Primitiva P: decrementa o valor inteiro e testa se menor que zero Sim: processo é posto para dormir (sleep) sem continuar a operação P Não: segue adiante Primitiva V: incrementa o valor inteiro e verifica se tem processos esperando no semáforo Sim: um é escolhido para continuar a operação P que iniciou previamente Não: segue adiante P(s): s.valor = s.valor 1; se s.valor < 0 { Insere processo P em s.fila Bloqueia processo P (sleep); V(s): s.valor = s.valor + 1 se s.valor <=0 { Retira um processo P de s.fila; Acorda processo P (wakeup); IMPORTANTE: atentar para as seções s na implementação de P(s) e V(s). As ações são feitas de forma indivisível para evitar condições de corrida Sistemas Operacionais I 17 Sistemas Operacionais I 18 Tipos e empregos de semáforos Leituras complementares Dependendo dos valores assumidos por s.valor Semáforos binários: s.valor = 1 Semáforos contadores: s.valor = n Emprego: Exclusão mútua: semáforos binários Controle de recursos: semáforos contadores Sincronização entre processos É isto que diferencia de travas (locks) Garantir que um processo pode prosseguir após uma condição se tornar verdadeira A. Tanenbaum. Sistemas Operacionais Modernos (3 a edição), Pearson Brasil, 010. Capítulo : seções 31.3.1 a 37.3.7 A. Silberchatz, P. Galvin; Sistemas Operacionais. (7 a edição). Campus, 008. Capítulo 6 (seções 6.1, 6., 6.4, 6.5 e 6.7) R. Oliveira, A. Carissimi, S. Toscani; Sistemas Operacionais. Editora Bookman 4 a edição, 010 Capítulo 3 (seções 3.1 a 3.7 e 3.10) Muito mais sobre semáforos (e outras primitivas) em INF01151 Sistemas Operacionais II Sistemas Operacionais I 19 Sistemas Operacionais I 0
Mas, espera ativa nem sempre é um problema O caso Missão Mars pathfinder: robô sojourner Em multiprocessadores (multicore) o busy wait pode ser interessante Há outro processador para liberar o recurso O custo de chaveamento pode não compensar (relação com o tamanho da seção ) Porém viola a regra sobre fazer suposições sobre processadores Possibilidade: primitiva trylock Faz busy wait por um período de tempo, se durante esse período o mutex não tiver sido liberado bloqueia (sleep) O programador escolhe entre trylock e lock Problema é dimensionar o período de tempo Compromisso entre o tamanho da seção, tempo de chaveamento de contexto e tempo estimado de espera O problema: A sonda, depois de algum tempo da missão iniciou, de forma não determinística, a fazer resets e se autoinicializar. A cada reset, os dados coletados e não transmitidos eram perdidos. Sistemas Operacionais I 1 Sistemas Operacionais I O problema do robô sojourner Uma nova versão para lock e unlock Thread 1: controle do barramento (alta prioridade) Transferência de dados de controle em um barramento de informações Thread : transmissão de dados (média prioridade) Thread 3: coleta de dados meteorológicos (baixa prioridade) Coleta dados meteorológicos e os publica no barramento de informações lock ( bus); preempção preempção lock ( bus); Watch dog (hardware) RESET T 1 T T 3 Funciona? lock_t flag=0; lock(flag); Seção unlock(flag); lock: tst register,flag cmp register,0 jnz entra call sleep jmp lock entra: unlock: mov flag,0 call wakeup O problema: Não prevê como memorizar o sinal de acordar Condição de corrida Situação: - P 1 executa o lock, entra na seção e perde o processador antes de liberar. -P executa o lock e perde o processador depois do JNZ e antes do CALL -Estava indo dormir, mas ainda não dormiu (não está na fila dos dorminhocos ) - P 1 oma a execução, faz o unlock, mas não libera P porque ele ainda não está na fila. -P oma execução, vai dormir (CALL), e perde o sinal de acordar Sistemas Operacionais I 3 Sistemas Operacionais I 4